Initial revision
authorJeremy Laine <jeremy.laine@m4x.org>
Mon, 1 Dec 2003 19:14:15 +0000 (19:14 +0000)
committerJeremy Laine <jeremy.laine@m4x.org>
Mon, 1 Dec 2003 19:14:15 +0000 (19:14 +0000)
89 files changed:
ekit/EkitAppletDemo.html [new file with mode: 0644]
ekit/MakeEkit.ant [new file with mode: 0644]
ekit/MakeEkit.bat [new file with mode: 0755]
ekit/MakeEkit.csh [new file with mode: 0755]
ekit/MakeEkitApplet.ant [new file with mode: 0644]
ekit/MakeEkitApplet.bat [new file with mode: 0755]
ekit/MakeEkitApplet.csh [new file with mode: 0755]
ekit/RunEkit.bat [new file with mode: 0755]
ekit/RunEkit.csh [new file with mode: 0644]
ekit/RunEkitApplet.csh [new file with mode: 0644]
ekit/com/hexidec/ekit/Ekit.java [new file with mode: 0644]
ekit/com/hexidec/ekit/EkitApplet.java [new file with mode: 0644]
ekit/com/hexidec/ekit/EkitCore.java [new file with mode: 0644]
ekit/com/hexidec/ekit/EkitCore_Basic.java [new file with mode: 0644]
ekit/com/hexidec/ekit/EkitCore_Spell.java [new file with mode: 0644]
ekit/com/hexidec/ekit/LanguageResources.properties [new file with mode: 0644]
ekit/com/hexidec/ekit/LanguageResources_de_DE.properties [new file with mode: 0644]
ekit/com/hexidec/ekit/LanguageResources_en_UK.properties [new file with mode: 0644]
ekit/com/hexidec/ekit/LanguageResources_en_US.properties [new file with mode: 0644]
ekit/com/hexidec/ekit/LanguageResources_es_ES.properties [new file with mode: 0644]
ekit/com/hexidec/ekit/LanguageResources_es_MX.properties [new file with mode: 0644]
ekit/com/hexidec/ekit/LanguageResources_fi_FI.properties [new file with mode: 0644]
ekit/com/hexidec/ekit/LanguageResources_fr_FR.properties [new file with mode: 0644]
ekit/com/hexidec/ekit/LanguageResources_hu_HU.properties [new file with mode: 0644]
ekit/com/hexidec/ekit/LanguageResources_it_CH.properties [new file with mode: 0644]
ekit/com/hexidec/ekit/LanguageResources_it_IT.properties [new file with mode: 0644]
ekit/com/hexidec/ekit/LanguageResources_nl_NL.properties [new file with mode: 0644]
ekit/com/hexidec/ekit/LanguageResources_no_NO.properties [new file with mode: 0644]
ekit/com/hexidec/ekit/LanguageResources_pt_BR.properties [new file with mode: 0644]
ekit/com/hexidec/ekit/LanguageResources_pt_PT.properties [new file with mode: 0644]
ekit/com/hexidec/ekit/LanguageResources_sl_SI.properties [new file with mode: 0644]
ekit/com/hexidec/ekit/LanguageResources_zh_CN.properties [new file with mode: 0644]
ekit/com/hexidec/ekit/README [new file with mode: 0644]
ekit/com/hexidec/ekit/TreePilot.properties [new file with mode: 0644]
ekit/com/hexidec/ekit/action/CustomAction.java [new file with mode: 0644]
ekit/com/hexidec/ekit/action/FormatAction.java [new file with mode: 0644]
ekit/com/hexidec/ekit/action/ListAutomationAction.java [new file with mode: 0644]
ekit/com/hexidec/ekit/action/StylesAction.java [new file with mode: 0644]
ekit/com/hexidec/ekit/component/ExtendedHTMLDocument.java [new file with mode: 0644]
ekit/com/hexidec/ekit/component/ExtendedHTMLEditorKit.java [new file with mode: 0644]
ekit/com/hexidec/ekit/component/FileDialog.java [new file with mode: 0644]
ekit/com/hexidec/ekit/component/FontSelectorDialog.java [new file with mode: 0644]
ekit/com/hexidec/ekit/component/HTMLUtilities.java [new file with mode: 0644]
ekit/com/hexidec/ekit/component/ImageDialog.java [new file with mode: 0644]
ekit/com/hexidec/ekit/component/ImageFileChooser.java [new file with mode: 0644]
ekit/com/hexidec/ekit/component/ImageFileChooserPreview.java [new file with mode: 0644]
ekit/com/hexidec/ekit/component/JButtonNoFocus.java [new file with mode: 0644]
ekit/com/hexidec/ekit/component/JComboBoxNoFocus.java [new file with mode: 0644]
ekit/com/hexidec/ekit/component/JToggleButtonNoFocus.java [new file with mode: 0644]
ekit/com/hexidec/ekit/component/MutableFilter.java [new file with mode: 0644]
ekit/com/hexidec/ekit/component/PropertiesDialog.java [new file with mode: 0644]
ekit/com/hexidec/ekit/component/RelativeImageView.java [new file with mode: 0644]
ekit/com/hexidec/ekit/component/SearchDialog.java [new file with mode: 0644]
ekit/com/hexidec/ekit/component/SimpleInfoDialog.java [new file with mode: 0644]
ekit/com/hexidec/ekit/component/TableInputDialog.java [new file with mode: 0644]
ekit/com/hexidec/ekit/component/UserInputAnchorDialog.java [new file with mode: 0644]
ekit/com/hexidec/ekit/component/UserInputDialog.java [new file with mode: 0644]
ekit/com/hexidec/ekit/ekit.manifest [new file with mode: 0644]
ekit/com/hexidec/ekit/icons/AnchorHK.gif [new file with mode: 0644]
ekit/com/hexidec/ekit/icons/BoldHK.gif [new file with mode: 0644]
ekit/com/hexidec/ekit/icons/ClearFormatHK.gif [new file with mode: 0644]
ekit/com/hexidec/ekit/icons/CopyHK.gif [new file with mode: 0644]
ekit/com/hexidec/ekit/icons/CutHK.gif [new file with mode: 0644]
ekit/com/hexidec/ekit/icons/ItalicHK.gif [new file with mode: 0644]
ekit/com/hexidec/ekit/icons/NewHK.gif [new file with mode: 0644]
ekit/com/hexidec/ekit/icons/OListHK.gif [new file with mode: 0644]
ekit/com/hexidec/ekit/icons/OpenHK.gif [new file with mode: 0644]
ekit/com/hexidec/ekit/icons/PasteHK.gif [new file with mode: 0644]
ekit/com/hexidec/ekit/icons/SaveHK.gif [new file with mode: 0644]
ekit/com/hexidec/ekit/icons/SourceHK.gif [new file with mode: 0644]
ekit/com/hexidec/ekit/icons/StrikeHK.gif [new file with mode: 0644]
ekit/com/hexidec/ekit/icons/SubHK.gif [new file with mode: 0644]
ekit/com/hexidec/ekit/icons/SuperHK.gif [new file with mode: 0644]
ekit/com/hexidec/ekit/icons/UListHK.gif [new file with mode: 0644]
ekit/com/hexidec/ekit/icons/UnderlineHK.gif [new file with mode: 0644]
ekit/com/hexidec/ekit/materials/FAQ_Factory/TaggingDriver/TaggingDriverServlet.java [new file with mode: 0644]
ekit/com/hexidec/ekit/materials/LGPL [new file with mode: 0644]
ekit/com/hexidec/util/Base64Codec.java [new file with mode: 0644]
ekit/com/hexidec/util/CMUS.proposal.txt [new file with mode: 0644]
ekit/com/hexidec/util/CMUScodec.java [new file with mode: 0644]
ekit/com/hexidec/util/Cartesian.java [new file with mode: 0644]
ekit/com/hexidec/util/DMCScodec.java [new file with mode: 0644]
ekit/com/hexidec/util/MutableFilter.java [new file with mode: 0644]
ekit/com/hexidec/util/PatternReplacer.java [new file with mode: 0644]
ekit/com/hexidec/util/Translatrix.java [new file with mode: 0644]
ekit/com/hexidec/util/TreeSpider$FileTreeComparator.class [new file with mode: 0644]
ekit/com/hexidec/util/TreeSpider.class [new file with mode: 0644]
ekit/com/hexidec/util/TreeSpider.java [new file with mode: 0644]
ekit/ekit.css [new file with mode: 0644]

diff --git a/ekit/EkitAppletDemo.html b/ekit/EkitAppletDemo.html
new file mode 100644 (file)
index 0000000..9736cfc
--- /dev/null
@@ -0,0 +1,49 @@
+<HTML>\r
+<HEAD>\r
+<TITLE>Ekit Applet Demo</TITLE>\r
+</HEAD>\r
+<BODY>\r
+<H1>Ekit Applet Demo</H1>\r
+<BR>\r
+<SCRIPT LANGUAGE="JavaScript">\r
+       var _info = navigator.userAgent;\r
+       var _ns = false;\r
+       var _ie = (_info.indexOf("MSIE") > 0 && _info.indexOf("Win") > 0 && _info.indexOf("Windows 3.1") < 0);\r
+</SCRIPT>\r
+<SCRIPT LANGUAGE="JavaScript1.1">\r
+       var _ns = (navigator.appName.indexOf("Netscape") >= 0 && ((_info.indexOf("Win") > 0 && _info.indexOf("Win16") < 0 && java.lang.System.getProperty("os.version").indexOf("3.5") < 0) || (_info.indexOf("Sun") > 0) || (_info.indexOf("Linux") > 0)));\r
+</SCRIPT>\r
+<SCRIPT LANGUAGE="JavaScript">\r
+       if      (_ie == true) document.writeln('<OBJECT ID="Ekit" classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93" WIDTH="560" HEIGHT="400" codebase="http://java.sun.com/products/plugin/1.4/jinstall-14-win32.cab#Version=1,4,0,0"><NOEMBED><XMP>');\r
+       else if (_ns == true) document.writeln('<EMBED NAME="Ekit" type="application/x-java-applet;version=1.4" CODE="com.hexidec.ekit.EkitApplet.class" ARCHIVE="ekitapplet.jar" WIDTH="560" HEIGHT="400" SCRIPTABLE="true" pluginspage="http://java.sun.com/products/plugin/1.4/plugin-install.html"><NOEMBED><XMP>');\r
+</SCRIPT>\r
+<APPLET CODEBASE="." CODE="com.hexidec.ekit.EkitApplet.class" ARCHIVE="ekitapplet.jar" NAME="Ekit" WIDTH="560" HEIGHT="400" MAYSCRIPT></XMP>\r
+       <PARAM NAME="codebase" VALUE=".">\r
+       <PARAM NAME="code" VALUE="com.hexidec.ekit.EkitApplet.class">\r
+       <PARAM NAME="archive" VALUE="ekitapplet.jar">\r
+       <PARAM NAME="name" VALUE="Ekit">\r
+       <PARAM NAME="type" VALUE="application/x-java-applet;version=1.4">\r
+       <PARAM NAME="scriptable" VALUE="true">\r
+       <PARAM NAME="DOCUMENT" VALUE="PGh0bWw+DQogIDxoZWFkPg0KICAgIA0KICA8L2hlYWQ+DQogIDxib2R5Pg0KICAgIDxoMj4NCiAgICAgIEVraXQgMC45Zw0KICAgIDwvaDI+DQogICAgPHRhYmxlIGJvcmRlcj0iMSIgd2lkdGg9IjgwJSI+DQogICAgICA8dHI+DQogICAgICAgIDx0ZD4NCiAgICAgICAgICA8Yj5UYWJsZXM8L2I+DQogICAgICAgIDwvdGQ+DQogICAgICAgIDx0ZD4NCiAgICAgICAgICA8Zm9udCBjb2xvcj0iIzAwODAwMCI+SW5zZXJ0PC9mb250Pi88Zm9udCBjb2xvcj0iIzgwMDAwMCI+RGVsZXRlPC9mb250Pg0KIFJvd3MgJmFtcDsgQ29sdW1ucw0KICAgICAgICA8L3RkPg0KICAgICAgPC90cj4NCiAgICAgIDx0cj4NCiAgICAgICAgPHRkPg0KICAgICAgICAgIDxiPkxpc3RzPC9iPg0KICAgICAgICA8L3RkPg0KICAgICAgICA8dGQ+DQogICAgICAgICAgPGk+QXV0b21hdGljYWxseTwvaT4gY3JlYXRlIG5ldyBidWxsZXRzDQogICAgICAgIDwvdGQ+DQogICAgICA8L3RyPg0KICAgICAgPHRyPg0KICAgICAgICA8dGQ+DQogICAgICAgICAgPGI+RG9jdW1lbnRzPC9iPg0KICAgICAgICA8L3RkPg0KICAgICAgICA8dGQ+DQogICAgICAgICAgTG9hZCBhbmQgU2F2ZSA8YmlnPjxmb250IGZhY2U9IkFtZWxpYSBCVCI+QmFzZTY0PC9mb250PjwvYmlnPiANCiAgICAgICAgICBlbmNvZGVkIHRleHRzDQogICAgICAgIDwvdGQ+DQogICAgICA8L3RyPg0KICAgIDwvdGFibGU+DQogICAgPHVsPg0KICAgICAgPGxpPg0KICAgICAgICBQb3dlcmZ1bA0KICAgICAgPC9saT4NCiAgICAgIDxsaT4NCiAgICAgICAgRmxleGlibGUNCiAgICAgIDwvbGk+DQogICAgICA8bGk+DQogICAgICAgIEZyZWUNCiAgICAgIDwvbGk+DQogICAgICA8bGk+DQogICAgICAgIFNvdXJjZSBpbmNsdWRlZA0KICAgICAgPC9saT4NCiAgICA8L3VsPg0KICAgIDxwPg0KICAgICAgJiMxNjA7DQogICAgPC9wPg0KICA8L2JvZHk+DQo8L2h0bWw+DQo=">\r
+       <PARAM NAME="BASE64" VALUE="true">\r
+       <PARAM NAME="STYLESHEET" VALUE="ekit.css">\r
+       <PARAM NAME="LANGCODE" VALUE="en">\r
+       <PARAM NAME="LANGCOUNTRY" VALUE="US">\r
+       <PARAM NAME="TOOLBAR" VALUE="true">\r
+       <PARAM NAME="SOURCEVIEW" VALUE="false">\r
+       <PARAM NAME="EXCLUSIVE" VALUE="true">\r
+       <PARAM NAME="MENUICONS" VALUE="true">\r
+       <PARAM NAME="MENU_EDIT" VALUE="true">\r
+       <PARAM NAME="MENU_VIEW" VALUE="true">\r
+       <PARAM NAME="MENU_FONT" VALUE="true">\r
+       <PARAM NAME="MENU_FORMAT" VALUE="true">\r
+       <PARAM NAME="MENU_INSERT" VALUE="true">\r
+       <PARAM NAME="MENU_TABLE" VALUE="true">\r
+       <PARAM NAME="MENU_FORMS" VALUE="true">\r
+       <PARAM NAME="MENU_SEARCH" VALUE="true">\r
+       <PARAM NAME="MENU_TOOLS" VALUE="true">\r
+       <PARAM NAME="MENU_HELP" VALUE="true">\r
+</APPLET>\r
+</NOEMBED></EMBED></OBJECT>\r
+</BODY>\r
+</HTML>\r
diff --git a/ekit/MakeEkit.ant b/ekit/MakeEkit.ant
new file mode 100644 (file)
index 0000000..aa9a739
--- /dev/null
@@ -0,0 +1,37 @@
+<project name="Ekit" default="fullbuild" basedir=".">\r
+       <property name="packagedir" location="com/hexidec"/>\r
+       <target name="initialise">\r
+               <delete file="ekit.jar"/>\r
+               <delete>\r
+                       <fileset dir="${packagedir}/ekit/" includes="**/*.class"/>\r
+               </delete>\r
+               <delete file="${packagedir}/util/Translatrix.class"/>\r
+       </target>\r
+       <target name="compile" description="Compile code">\r
+               <javac compiler="modern">\r
+                       <src path="${packagedir}"/>\r
+                       <include name="util/Translatrix.java"/>\r
+                       <include name="ekit/action/*.java"/>\r
+                       <include name="ekit/component/*.java"/>\r
+                       <include name="ekit/EkitCore.java"/>\r
+                       <include name="ekit/Ekit.java"/>\r
+               </javac>\r
+       </target>\r
+       <target name="distribute" depends="compile" description="Jar code and ancillary files">\r
+               <jar\r
+                       destfile="ekit.jar"\r
+                       basedir="."\r
+                       manifest="com/hexidec/ekit/ekit.manifest"\r
+                       includes="com/hexidec/ekit/*.class,com/hexidec/ekit/action/*.class,com/hexidec/ekit/component/*.class,com/hexidec/ekit/icons/*.gif,com/hexidec/ekit/*.properties,com/hexidec/util/Translatrix.class"/>\r
+               <chmod file="ekit.jar" perm="755"/>\r
+       </target>\r
+       <target name="cleanup" description="Delete classes">\r
+               <delete>\r
+                       <fileset dir="${packagedir}/ekit/" includes="**/*.class"/>\r
+               </delete>\r
+               <delete file="${packagedir}/util/Translatrix.class"/>\r
+       </target>\r
+       <target name="fullbuild" depends="initialise,compile,distribute,cleanup">\r
+               <echo message="Full Build Complete"/>\r
+       </target>\r
+</project>\r
diff --git a/ekit/MakeEkit.bat b/ekit/MakeEkit.bat
new file mode 100755 (executable)
index 0000000..312b315
--- /dev/null
@@ -0,0 +1,61 @@
+@set inputmode=mode%1
+@if %inputmode% == modespell goto spellmaker
+@goto basicmaker
+:basicmaker
+  @echo =========================
+  @echo Basic version compilation
+  @echo =========================
+  @set compilemode=basic
+  @set additionalfiles=
+  @echo [] creating core...
+  @copy /Y com\hexidec\ekit\EkitCore_Basic.java com\hexidec\ekit\EkitCore.java
+  @if errorlevel 2 goto failure
+  @goto compilecore
+:spellmaker
+  @echo ==============================
+  @echo Spellcheck version compilation
+  @echo ==============================
+  @set compilemode=spell
+  @set additionalfiles=com\swabunga\spell\engine\*.class com\swabunga\spell\engine\*.properties com\swabunga\spell\engine\dictionary\* com\swabunga\spell\event\*.class com\swabunga\spell\swing\*.class com\swabunga\spell\swing\*.properties
+  @echo [] creating core...
+  @copy /Y com\hexidec\ekit\EkitCore_Spell.java com\hexidec\ekit\EkitCore.java
+  @if errorlevel 2 goto failure
+  @goto compilecore
+:compilecore
+  @echo [] compiling core...
+  @javac -deprecation com\hexidec\ekit\EkitCore.java
+  @if errorlevel 1 goto failure
+  @goto compileapp
+:compileapp
+  @echo [] compiling application...
+  @javac com\hexidec\ekit\Ekit.java
+  @if errorlevel 2 goto failure
+  @goto makejar
+:makejar
+  @echo [] jarring...
+  @jar cmf com\hexidec\ekit\ekit.manifest ekit.jar com\hexidec\ekit\*.class com\hexidec\ekit\action\*.class com\hexidec\ekit\component\*.class com\hexidec\ekit\icons\*.gif com\hexidec\ekit\*.properties com\hexidec\util\Base64Codec.class com\hexidec\util\Translatrix.class %additionalfiles%
+  @if errorlevel 1 goto failure
+  @goto cleanup
+:failure
+  @echo [*] make failed with an error level of %errorlevel%
+  @goto cleanup
+:cleanup
+  @echo [] cleaning up Ekit classes...
+  @del com\hexidec\ekit\*.class
+  @del com\hexidec\ekit\action\*.class
+  @del com\hexidec\ekit\component\*.class
+  @del com\hexidec\util\Base64Codec.class
+  @del com\hexidec\util\Translatrix.class
+  @if %compilemode% == spell goto spellpurge
+  @goto finish
+:spellpurge
+  @echo [] cleaning up spellcheck classes...
+  @del com\swabunga\spell\engine\*.class
+  @del com\swabunga\spell\event\*.class
+  @del com\swabunga\spell\swing\*.class
+  @goto finish
+:finish
+  @set inputmode=
+  @set compilemode=
+  @set additionalfiles=
+  @echo [] finished
diff --git a/ekit/MakeEkit.csh b/ekit/MakeEkit.csh
new file mode 100755 (executable)
index 0000000..464b042
--- /dev/null
@@ -0,0 +1,63 @@
+#! /bin/csh
+set inputmode=mode$1
+if $inputmode == modespell goto spellmaker
+goto basicmaker
+basicmaker:
+  echo =========================
+  echo Basic version compilation
+  echo =========================
+  set mode=basic
+  echo [] creating core...
+  cp com/hexidec/ekit/EkitCore_Basic.java com/hexidec/ekit/EkitCore.java
+  if $status == 0 goto compilecore
+  goto failure
+spellmaker:
+  echo ==============================
+  echo Spellcheck version compilation
+  echo ==============================
+  set mode=spell
+  echo [] creating core...
+  cp com/hexidec/ekit/EkitCore_Spell.java com/hexidec/ekit/EkitCore.java
+  if $status == 0 goto compilecore
+  goto failure
+compilecore:
+  echo [] compiling core...
+  javac com/hexidec/ekit/EkitCore.java
+  if $status == 0 goto compileapp
+  goto failure
+compileapp:
+  echo [] compiling application...
+  javac com/hexidec/ekit/Ekit.java
+  if $status == 0 goto makejar
+  goto failure
+makejar:
+  echo [] jarring...
+  if $mode == basic jar cmf com/hexidec/ekit/ekit.manifest ekit.jar com/hexidec/ekit/*.class com/hexidec/ekit/action/*.class com/hexidec/ekit/component/*.class com/hexidec/util/Base64Codec.class com/hexidec/util/Translatrix.class com/hexidec/ekit/icons/*.gif com/hexidec/ekit/*.properties
+  if $mode == spell jar cmf com/hexidec/ekit/ekit.manifest ekit.jar com/hexidec/ekit/*.class com/hexidec/ekit/action/*.class com/hexidec/ekit/component/*.class com/hexidec/util/Base64Codec.class com/hexidec/util/Translatrix.class com/hexidec/ekit/icons/*.gif com/hexidec/ekit/*.properties com/swabunga/spell/engine/*.class com/swabunga/spell/engine/*.properties com/swabunga/spell/engine/dictionary/* com/swabunga/spell/event/*.class com/swabunga/spell/swing/*.class com/swabunga/spell/swing/*.properties
+  if $status == 0 goto modjar
+  goto failure
+modjar:
+  echo [] modifying jar permissions...
+  chmod 755 ekit.jar
+  if $status == 0 goto cleanup
+  goto failure
+cleanup:
+  echo [] cleaning up Ekit classes...
+  rm com/hexidec/ekit/*.class
+  rm com/hexidec/ekit/action/*.class
+  rm com/hexidec/ekit/component/*.class
+  rm com/hexidec/util/Base64Codec.class
+  rm com/hexidec/util/Translatrix.class
+  if $mode == spell goto spellpurge
+  goto finish
+spellpurge:
+  echo [] cleaning up spellcheck classes...
+  rm com/swabunga/spell/engine/*.class
+  rm com/swabunga/spell/event/*.class
+  rm com/swabunga/spell/swing/*.class
+  goto finish
+failure:
+  echo [*] make failed with an error level of $status
+  goto finish
+finish:
+  echo [] finished
diff --git a/ekit/MakeEkitApplet.ant b/ekit/MakeEkitApplet.ant
new file mode 100644 (file)
index 0000000..6eadb11
--- /dev/null
@@ -0,0 +1,38 @@
+<project name="EkitApplet" default="fullbuild" basedir=".">\r
+       <property name="packagedir" location="com/hexidec"/>\r
+       <target name="initialise">\r
+               <delete file="ekitapplet.jar"/>\r
+               <delete>\r
+                       <fileset dir="${packagedir}/ekit/" includes="**/*.class"/>\r
+               </delete>\r
+               <delete file="${packagedir}/util/Translatrix.class"/>\r
+       </target>\r
+       <target name="compile" description="Compile code">\r
+               <javac compiler="modern">\r
+                       <src path="${packagedir}"/>\r
+                       <include name="util/Base64Codec.java"/>\r
+                       <include name="util/Translatrix.java"/>\r
+                       <include name="ekit/action/*.java"/>\r
+                       <include name="ekit/component/*.java"/>\r
+                       <include name="ekit/EkitCore.java"/>\r
+                       <include name="ekit/EkitApplet.java"/>\r
+               </javac>\r
+       </target>\r
+       <target name="distribute" depends="compile" description="Jar code and ancillary files">\r
+               <jar\r
+                       destfile="ekitapplet.jar"\r
+                       basedir="."\r
+                       includes="com/hexidec/ekit/*.class,com/hexidec/ekit/action/*.class,com/hexidec/ekit/component/*.class,com/hexidec/ekit/icons/*.gif,com/hexidec/ekit/*.properties,com/hexidec/util/Base64Codec.class,com/hexidec/util/Translatrix.class"/>\r
+               <chmod file="ekitapplet.jar" perm="755"/>\r
+       </target>\r
+       <target name="cleanup" description="Delete classes">\r
+               <delete>\r
+                       <fileset dir="${packagedir}/ekit/" includes="**/*.class"/>\r
+               </delete>\r
+               <delete file="${packagedir}/util/Base64Codec.class"/>\r
+               <delete file="${packagedir}/util/Translatrix.class"/>\r
+       </target>\r
+       <target name="fullbuild" depends="initialise,compile,distribute,cleanup">\r
+               <echo message="Full Build Complete"/>\r
+       </target>\r
+</project>\r
diff --git a/ekit/MakeEkitApplet.bat b/ekit/MakeEkitApplet.bat
new file mode 100755 (executable)
index 0000000..16e929c
--- /dev/null
@@ -0,0 +1,58 @@
+@set inputmode=mode%1\r
+@if %inputmode% == modespell goto spellmaker\r
+@goto basicmaker\r
+:basicmaker\r
+  @echo =========================\r
+  @echo Basic version compilation\r
+  @echo =========================\r
+  @set mode=basic\r
+  @set additionalfiles=\r
+  @echo [] creating core...\r
+  @copy /Y com\hexidec\ekit\EkitCore_Basic.java com\hexidec\ekit\EkitCore.java\r
+  @if errorlevel 1 goto failure\r
+  @goto compilecore\r
+:spellmaker\r
+  @echo ==============================\r
+  @echo Spellcheck version compilation\r
+  @echo ==============================\r
+  @set mode=spell\r
+  @set additionalfiles=com\swabunga\spell\engine\*.class com\swabunga\spell\engine\*.properties com\swabunga\spell\engine\dictionary\* com\swabunga\spell\event\*.class com\swabunga\spell\swing\*.class com\swabunga\spell\swing\*.properties\r
+  @echo [] creating core...\r
+  @copy /Y com\hexidec\ekit\EkitCore_Spell.java com\hexidec\ekit\EkitCore.java\r
+  @if errorlevel 1 goto failure\r
+  @goto compilecore\r
+:compilecore\r
+  @echo [] compiling core...\r
+  @javac com\hexidec\ekit\EkitCore.java\r
+  @if errorlevel 1 goto failure\r
+  @goto compileapp\r
+:compileapp\r
+  @echo [] compiling application...\r
+  @javac com\hexidec\ekit\EkitApplet.java\r
+  @if errorlevel 1 goto failure\r
+  @goto makejar\r
+:makejar\r
+  @echo [] jarring...\r
+  @jar cf ekitapplet.jar com\hexidec\ekit\*.class com\hexidec\ekit\action\*.class com\hexidec\ekit\component\*.class com\hexidec\ekit\icons\*.gif com\hexidec\ekit\*.properties com\hexidec\util\Base64Codec.class com\hexidec\util\Translatrix.class %additionalfiles%\r
+  @if errorlevel 1 goto failure\r
+  @goto cleanup\r
+:failure\r
+  @echo [*] make failed with an error level of %errorlevel%\r
+  @goto cleanup\r
+:cleanup\r
+  @echo [] cleaning up Ekit classes...\r
+  @del com\hexidec\ekit\*.class\r
+  @del com\hexidec\ekit\action\*.class\r
+  @del com\hexidec\ekit\component\*.class\r
+  @del com\hexidec\util\Base64Codec.class\r
+  @del com\hexidec\util\Translatrix.class\r
+  @if %mode% == spell goto spellpurge\r
+  @goto finish\r
+:spellpurge\r
+  @echo [] cleaning up spellcheck classes...\r
+  @del com\swabunga\spell\engine\*.class\r
+  @del com\swabunga\spell\event\*.class\r
+  @del com\swabunga\spell\swing\*.class\r
+  @goto finish\r
+:finish\r
+  @echo [] finished\r
diff --git a/ekit/MakeEkitApplet.csh b/ekit/MakeEkitApplet.csh
new file mode 100755 (executable)
index 0000000..b7c2b8a
--- /dev/null
@@ -0,0 +1,63 @@
+#! /bin/csh
+set inputmode=mode$1
+if $inputmode == modespell goto spellmaker
+goto basicmaker
+basicmaker:
+  echo =========================
+  echo Basic version compilation
+  echo =========================
+  set mode=basic
+  echo [] creating core...
+  cp com/hexidec/ekit/EkitCore_Basic.java com/hexidec/ekit/EkitCore.java
+  if $status == 0 goto compilecore
+  goto failure
+spellmaker:
+  echo ==============================
+  echo Spellcheck version compilation
+  echo ==============================
+  set mode=spell
+  echo [] creating core...
+  cp com/hexidec/ekit/EkitCore_Spell.java com/hexidec/ekit/EkitCore.java
+  if $status == 0 goto compilecore
+  goto failure
+compilecore:
+  echo [] compiling core...
+  javac com/hexidec/ekit/EkitCore.java
+  if $status == 0 goto compileapp
+  goto failure
+compileapp:
+  echo [] compiling application...
+  javac com/hexidec/ekit/EkitApplet.java
+  if $status == 0 goto makejar
+  goto failure
+makejar:
+  echo [] jarring...
+  if $mode == basic jar cf ekitapplet.jar com/hexidec/ekit/*.class com/hexidec/ekit/action/*.class com/hexidec/ekit/component/*.class com/hexidec/util/Base64Codec.class com/hexidec/util/Translatrix.class com/hexidec/ekit/icons/*.gif com/hexidec/ekit/*.properties
+  if $mode == spell jar cf ekitapplet.jar com/hexidec/ekit/*.class com/hexidec/ekit/action/*.class com/hexidec/ekit/component/*.class com/hexidec/util/Base64Codec.class com/hexidec/util/Translatrix.class com/hexidec/ekit/icons/*.gif com/hexidec/ekit/*.properties com/swabunga/spell/engine/*.class com/swabunga/spell/engine/*.properties com/swabunga/spell/engine/dictionary/* com/swabunga/spell/event/*.class com/swabunga/spell/swing/*.class com/swabunga/spell/swing/*.properties
+  if $status == 0 goto modjar
+  goto failure
+modjar:
+  echo [] modifying jar permissions...
+  chmod 755 ekitapplet.jar
+  if $status == 0 goto cleanup
+  goto failure
+cleanup:
+  echo [] cleaning up Ekit classes...
+  rm com/hexidec/ekit/*.class
+  rm com/hexidec/ekit/action/*.class
+  rm com/hexidec/ekit/component/*.class
+  rm com/hexidec/util/Base64Codec.class
+  rm com/hexidec/util/Translatrix.class
+  if $mode == spell goto spellpurge
+  goto finish
+spellpurge:
+  echo [] cleaning up spellcheck classes...
+  rm com/swabunga/spell/engine/*.class
+  rm com/swabunga/spell/event/*.class
+  rm com/swabunga/spell/swing/*.class
+  goto finish
+failure:
+  echo [*] make failed with an error level of $status
+  goto finish
+finish:
+  echo [] finished
diff --git a/ekit/RunEkit.bat b/ekit/RunEkit.bat
new file mode 100755 (executable)
index 0000000..eaa9754
--- /dev/null
@@ -0,0 +1 @@
+@java -jar ekit.jar com.hexidec.ekit.Ekit %1 %2 %3 %4 %5 %6 %7 %8 %9
\ No newline at end of file
diff --git a/ekit/RunEkit.csh b/ekit/RunEkit.csh
new file mode 100644 (file)
index 0000000..8592a9b
--- /dev/null
@@ -0,0 +1 @@
+java -jar ekit.jar com.hexidec.ekit.Ekit $1 $2 $3 $4 $5 $6 $7 $8 $9\r
diff --git a/ekit/RunEkitApplet.csh b/ekit/RunEkitApplet.csh
new file mode 100644 (file)
index 0000000..dd3bb47
--- /dev/null
@@ -0,0 +1 @@
+appletviewer EkitAppletDemo.html\r
diff --git a/ekit/com/hexidec/ekit/Ekit.java b/ekit/com/hexidec/ekit/Ekit.java
new file mode 100644 (file)
index 0000000..b72c209
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+GNU Lesser General Public License
+
+Ekit - Java Swing HTML Editor & Viewer
+Copyright (C) 2000-2003 Howard Kistler
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+package com.hexidec.ekit;
+
+import java.awt.BorderLayout;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.io.FileWriter;
+import javax.swing.JFrame;
+
+import com.hexidec.ekit.EkitCore;
+
+/** Ekit
+  * App for editing and saving HTML in a Java text component
+  *
+  * @author Howard Kistler
+  * @version 0.9e
+  *
+  * REQUIREMENTS
+  * Java 2 (JDK 1.3 or 1.4)
+  * Swing Library
+  */
+
+public class Ekit extends JFrame implements WindowListener
+{
+       private EkitCore ekitCore;
+
+       private File currentFile = (File)null;
+
+       /** Master Constructor
+         * @param sDocument         [String]  A text or HTML document to load in the editor upon startup.
+         * @param sStyleSheet       [String]  A CSS stylesheet to load in the editor upon startup.
+         * @param sRawDocument      [String]  A document encoded as a String to load in the editor upon startup.
+         * @param urlStyleSheet     [URL]     A URL reference to the CSS style sheet.
+         * @param showToolBar       [boolean] Specifies whether the app should include the toolbar.
+         * @param showViewSource    [boolean] Specifies whether or not to show the View Source window on startup.
+         * @param showMenuIcons     [boolean] Specifies whether or not to show icon pictures in menus.
+         * @param editModeExclusive [boolean] Specifies whether or not to use exclusive edit mode (recommended on).
+         * @param sLanguage         [String]  The language portion of the Internationalization Locale to run Ekit in.
+         * @param sCountry          [String]  The country portion of the Internationalization Locale to run Ekit in.
+         * @param base64            [boolean] Specifies whether the raw document is Base64 encoded or not.
+         * @param debugMode         [boolean] Specifies whether to show the Debug menu or not.
+         */
+       public Ekit(String sDocument, String sStyleSheet, String sRawDocument, URL urlStyleSheet, boolean showToolBar, boolean showViewSource, boolean showMenuIcons, boolean editModeExclusive, String sLanguage, String sCountry, boolean base64, boolean debugMode)
+       {
+               ekitCore = new EkitCore(sDocument, sStyleSheet, sRawDocument, urlStyleSheet, showViewSource, showMenuIcons, editModeExclusive, sLanguage, sCountry, base64, debugMode);
+
+               ekitCore.setFrame(this);
+
+               /* Add the components to the app */
+               this.getContentPane().setLayout(new BorderLayout());
+               this.getContentPane().add(ekitCore, BorderLayout.CENTER);
+               if(showToolBar)
+               {
+                       this.getContentPane().add(ekitCore.getToolBar(showToolBar), BorderLayout.NORTH);
+               }
+
+               this.setJMenuBar(ekitCore.getMenuBar());
+
+               this.addWindowListener(this);
+
+               this.updateTitle();
+               this.pack();
+               this.show();
+       }
+
+       public Ekit()
+       {
+               this(null, null, null, null, true, false, true, true, null, null, false, false);
+       }
+
+       /* WindowListener methods */
+       public void windowClosing(WindowEvent we)
+       {
+               this.dispose();
+               System.exit(0);
+       }
+       public void windowOpened(WindowEvent we)      { ; }
+       public void windowClosed(WindowEvent we)      { ; }
+       public void windowActivated(WindowEvent we)   { ; }
+       public void windowDeactivated(WindowEvent we) { ; }
+       public void windowIconified(WindowEvent we)   { ; }
+       public void windowDeiconified(WindowEvent we) { ; }
+
+       /** Convenience method for updating the application title bar
+         */
+       private void updateTitle()
+       {
+               this.setTitle(ekitCore.getAppName() + (currentFile == null ? "" : " - " + currentFile.getName()));
+       }
+
+       /** Main method
+         */
+       public static void main(String[] args)
+       {
+               if(args.length > 0)
+               {
+                       String sDocument = null;
+                       String sStyleSheet = null;
+                       String sRawDocument = null;
+                       URL urlStyleSheet = null;
+                       boolean includeToolBar = true;
+                       boolean includeViewSource = false;
+                       boolean includeMenuIcons = true;
+                       boolean modeExclusive = true;
+                       String sLang = null;
+                       String sCtry = null;
+                       boolean base64 = false;
+                       boolean debugOn = false;
+                       for(int i = 0; i < args.length; i++)
+                       {
+                               if     (args[i].equals("-t"))     { includeToolBar = true; }
+                               else if(args[i].equals("-T"))     { includeToolBar = false; }
+                               else if(args[i].equals("-s"))     { includeViewSource = true; }
+                               else if(args[i].equals("-S"))     { includeViewSource = false; }
+                               else if(args[i].equals("-m"))     { includeMenuIcons = true; }
+                               else if(args[i].equals("-M"))     { includeMenuIcons = false; }
+                               else if(args[i].equals("-x"))     { modeExclusive = true; }
+                               else if(args[i].equals("-X"))     { modeExclusive = false; }
+                               else if(args[i].equals("-b"))     { base64 = true; }
+                               else if(args[i].equals("-B"))     { base64 = false; }
+                               else if(args[i].startsWith("-f")) { sDocument = args[i].substring(2, args[i].length()); }
+                               else if(args[i].startsWith("-c")) { sStyleSheet = args[i].substring(2, args[i].length()); }
+                               else if(args[i].startsWith("-r")) { sRawDocument = args[i].substring(2, args[i].length()); }
+                               else if(args[i].startsWith("-u"))
+                               {
+                                       try
+                                       {
+                                               urlStyleSheet = new URL(args[i].substring(2, args[i].length()));
+                                       }
+                                       catch(MalformedURLException murle)
+                                       {
+                                               murle.printStackTrace(System.err);
+                                       }
+                               }
+                               else if(args[i].startsWith("-l"))
+                               {
+                                       if(args[i].indexOf('_') > -1)
+                                       {
+                                               sLang = args[i].substring(2, args[i].indexOf('_'));
+                                               sCtry = args[i].substring(args[i].indexOf('_') + 1, args[i].length());
+                                       }
+                               }
+                               else if(args[i].equals("-d"))     { debugOn = true; }
+                               else if(args[i].equals("-D"))     { debugOn = false; }
+                       }
+                       Ekit ekit = new Ekit(sDocument, sStyleSheet, sRawDocument, urlStyleSheet, includeToolBar, includeViewSource, includeMenuIcons, modeExclusive, sLang, sCtry, base64, debugOn);
+               }
+               else
+               {
+                       Ekit ekit = new Ekit();
+               }
+       }
+
+}
\ No newline at end of file
diff --git a/ekit/com/hexidec/ekit/EkitApplet.java b/ekit/com/hexidec/ekit/EkitApplet.java
new file mode 100644 (file)
index 0000000..9400970
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+GNU Lesser General Public License
+
+EkitApplet - Java Swing HTML Editor & Viewer Applet
+Copyright (C) 2000-2003 Howard Kistler
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+package com.hexidec.ekit;
+
+import java.awt.BorderLayout;
+import java.awt.Toolkit;
+import java.awt.event.KeyEvent;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Vector;
+import javax.swing.JApplet;
+import javax.swing.JLabel;
+
+import com.hexidec.ekit.EkitCore;
+
+/** EkitApplet
+  * Applet for editing and saving HTML in a Java browser component
+  *
+  * @author Howard Kistler
+  * @version 0.9e
+  *
+  * REQUIREMENTS
+  * Java 2 (JDK 1.3 or 1.4)
+  * Swing Library
+  */
+
+public class EkitApplet extends JApplet
+{
+       /* Components */
+       EkitCore ekitCore;
+
+       private JLabel jlblStatus;
+
+       /** Constructor
+         */
+       public EkitApplet()
+       {
+               getRootPane().putClientProperty("defeatSystemEventQueueCheck", Boolean.TRUE);
+       }
+
+       /** Applet Init
+         */
+       public void init()
+       {
+               String sRawDocument = this.getParameter("DOCUMENT");
+               String sStyleSheetRef = this.getParameter("STYLESHEET");
+               boolean base64 = ((this.getParameter("BASE64") != null) && this.getParameter("BASE64").equalsIgnoreCase("true"));
+               URL urlCSS = (URL)null;
+               try
+               {
+                       if(sStyleSheetRef != null && sStyleSheetRef.length() > 0)
+                       {
+                               urlCSS = new URL(this.getCodeBase(), sStyleSheetRef);
+                       }
+               }
+               catch(MalformedURLException murle)
+               {
+                       murle.printStackTrace(System.err);
+               }
+               boolean showToolBar = true;
+               if(this.getParameter("TOOLBAR") != null) { showToolBar = this.getParameter("TOOLBAR").equalsIgnoreCase("true"); }
+               boolean showViewSource = ((this.getParameter("SOURCEVIEW") != null && this.getParameter("SOURCEVIEW").equalsIgnoreCase("true")));
+               String sLanguage = this.getParameter("LANGCODE");
+               String sCountry = this.getParameter("LANGCOUNTRY");
+               boolean editModeExclusive = true;
+               if(this.getParameter("EXCLUSIVE") != null) { editModeExclusive = this.getParameter("EXCLUSIVE").equalsIgnoreCase("true"); }
+               boolean showMenuIcons = true;
+               if(this.getParameter("MENUICONS") != null) { showMenuIcons = this.getParameter("MENUICONS").equalsIgnoreCase("true"); }
+
+               ekitCore = new EkitCore(sRawDocument, urlCSS, showViewSource, showMenuIcons, editModeExclusive, sLanguage, sCountry, base64);
+
+               /* Obtain image servlet information */
+               ekitCore.setServletURL(this.getParameter("SERVLETURL"));
+               ekitCore.setImageDir(this.getParameter("IMAGEDIR"));            
+               ekitCore.setTreePilotSystemID(this.getParameter("SYSTEMID"));
+
+               /* Add menus, based on whether or not they are requested (all are shown by default) */
+               Vector vcMenus = new Vector();
+               if(this.getParameter("MENU_EDIT")   != null) { if(this.getParameter("MENU_EDIT").equalsIgnoreCase("true"))   { vcMenus.add(EkitCore.KEY_MENU_EDIT); } }   else { vcMenus.add(EkitCore.KEY_MENU_EDIT); }
+               if(this.getParameter("MENU_VIEW")   != null) { if(this.getParameter("MENU_VIEW").equalsIgnoreCase("true"))   { vcMenus.add(EkitCore.KEY_MENU_VIEW); } }   else { vcMenus.add(EkitCore.KEY_MENU_VIEW); }
+               if(this.getParameter("MENU_FONT")   != null) { if(this.getParameter("MENU_FONT").equalsIgnoreCase("true"))   { vcMenus.add(EkitCore.KEY_MENU_FONT); } }   else { vcMenus.add(EkitCore.KEY_MENU_FONT); }
+               if(this.getParameter("MENU_FORMAT") != null) { if(this.getParameter("MENU_FORMAT").equalsIgnoreCase("true")) { vcMenus.add(EkitCore.KEY_MENU_FORMAT); } } else { vcMenus.add(EkitCore.KEY_MENU_FORMAT); }
+               if(this.getParameter("MENU_INSERT") != null) { if(this.getParameter("MENU_INSERT").equalsIgnoreCase("true")) { vcMenus.add(EkitCore.KEY_MENU_INSERT); } } else { vcMenus.add(EkitCore.KEY_MENU_INSERT); }
+               if(this.getParameter("MENU_TABLE")  != null) { if(this.getParameter("MENU_TABLE").equalsIgnoreCase("true"))  { vcMenus.add(EkitCore.KEY_MENU_TABLE); } }  else { vcMenus.add(EkitCore.KEY_MENU_TABLE); }
+               if(this.getParameter("MENU_FORMS")  != null) { if(this.getParameter("MENU_FORMS").equalsIgnoreCase("true"))  { vcMenus.add(EkitCore.KEY_MENU_FORMS); } }  else { vcMenus.add(EkitCore.KEY_MENU_FORMS); }
+               if(this.getParameter("MENU_SEARCH") != null) { if(this.getParameter("MENU_SEARCH").equalsIgnoreCase("true")) { vcMenus.add(EkitCore.KEY_MENU_SEARCH); } } else { vcMenus.add(EkitCore.KEY_MENU_SEARCH); }
+               if(this.getParameter("MENU_TOOLS")  != null) { if(this.getParameter("MENU_TOOLS").equalsIgnoreCase("true"))  { vcMenus.add(EkitCore.KEY_MENU_TOOLS); } }  else { vcMenus.add(EkitCore.KEY_MENU_TOOLS); }
+               if(this.getParameter("MENU_HELP")   != null) { if(this.getParameter("MENU_HELP").equalsIgnoreCase("true"))   { vcMenus.add(EkitCore.KEY_MENU_HELP); } }   else { vcMenus.add(EkitCore.KEY_MENU_HELP); }
+               this.setJMenuBar(ekitCore.getCustomMenuBar(vcMenus));
+
+               jlblStatus = new JLabel();
+               
+               /* Add the components to the app */
+               this.getContentPane().setLayout(new BorderLayout());
+               this.getContentPane().add(ekitCore, BorderLayout.CENTER);
+               this.getContentPane().add(jlblStatus, BorderLayout.SOUTH);
+               if(showToolBar)
+               {
+                       Vector vcTools = new Vector();
+                       vcTools.add(EkitCore.KEY_TOOL_NEW);
+                       vcTools.add(EkitCore.KEY_TOOL_SEP);
+                       vcTools.add(EkitCore.KEY_TOOL_CUT);
+                       vcTools.add(EkitCore.KEY_TOOL_COPY);
+                       vcTools.add(EkitCore.KEY_TOOL_PASTE);
+                       vcTools.add(EkitCore.KEY_TOOL_SEP);
+                       vcTools.add(EkitCore.KEY_TOOL_BOLD);
+                       vcTools.add(EkitCore.KEY_TOOL_ITALIC);
+                       vcTools.add(EkitCore.KEY_TOOL_UNDERLINE);
+                       vcTools.add(EkitCore.KEY_TOOL_STRIKE);
+                       vcTools.add(EkitCore.KEY_TOOL_SUPER);
+                       vcTools.add(EkitCore.KEY_TOOL_SUB);
+                       vcTools.add(EkitCore.KEY_TOOL_ULIST);
+                       vcTools.add(EkitCore.KEY_TOOL_OLIST);
+                       vcTools.add(EkitCore.KEY_TOOL_SEP);
+                       vcTools.add(EkitCore.KEY_TOOL_CLEAR);
+                       vcTools.add(EkitCore.KEY_TOOL_SEP);
+                       vcTools.add(EkitCore.KEY_TOOL_ANCHOR);
+                       vcTools.add(EkitCore.KEY_TOOL_SEP);
+                       vcTools.add(EkitCore.KEY_TOOL_SOURCE);
+                       vcTools.add(EkitCore.KEY_TOOL_SEP);
+                       vcTools.add(EkitCore.KEY_TOOL_STYLES);
+                       this.getContentPane().add(ekitCore.getCustomToolBar(vcTools, showToolBar), BorderLayout.NORTH);
+               }
+       }
+
+       /* Applet methods */
+       public void start()   { ; }
+       public void stop()    { ; }
+       public void destroy() { ; }
+
+       /** Method for passing back the document text to the applet's container.
+         * This is the entire document, including the top-level HTML tags.
+         */
+       public String getDocumentText()
+       {
+               return ekitCore.getDocumentText();
+       }
+
+       /** Method for passing back the document body to the applet's container.
+         * This is only the text contained within the BODY tags.
+         */
+       public String getDocumentBody()
+       {
+               return ekitCore.getDocumentSubText("body");
+       }
+
+       /** Method for setting the document manually.
+         * Will need code in the web page to call this.
+         */
+       public void setDocumentText(String text)
+       {
+               ekitCore.setDocumentText(text);
+       }
+
+}
diff --git a/ekit/com/hexidec/ekit/EkitCore.java b/ekit/com/hexidec/ekit/EkitCore.java
new file mode 100644 (file)
index 0000000..ef23e15
--- /dev/null
@@ -0,0 +1,2836 @@
+/*
+GNU Lesser General Public License
+
+EkitCore - Base Java Swing HTML Editor & Viewer Class (Basic Version)
+Copyright (C) 2000-2003 Howard Kistler
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+package com.hexidec.ekit;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Cursor;
+import java.awt.Dimension;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.Image;
+import java.awt.Insets;
+import java.awt.Toolkit;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Reader;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.MalformedURLException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+import java.util.Vector;
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+import javax.swing.JDialog;
+import javax.swing.JEditorPane;
+import javax.swing.JFileChooser;
+import javax.swing.JFrame;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSplitPane;
+import javax.swing.JTextField;
+import javax.swing.JTextPane;
+import javax.swing.JToggleButton;
+import javax.swing.JToolBar;
+import javax.swing.KeyStroke;
+import javax.swing.event.CaretEvent;
+import javax.swing.event.CaretListener;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import javax.swing.event.UndoableEditEvent;
+import javax.swing.event.UndoableEditListener;
+import javax.swing.filechooser.FileFilter;
+import javax.swing.text.AttributeSet;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.ChangedCharSetException;
+import javax.swing.text.DefaultEditorKit;
+import javax.swing.text.DefaultStyledDocument;
+import javax.swing.text.Document;
+import javax.swing.text.Element;
+import javax.swing.text.PlainDocument;
+import javax.swing.text.Position;
+import javax.swing.text.Style;
+import javax.swing.text.StyleConstants;
+import javax.swing.text.StyledDocument;
+import javax.swing.text.StyledEditorKit;
+import javax.swing.text.StyledEditorKit.FontSizeAction;
+import javax.swing.text.html.HTML;
+import javax.swing.text.html.HTMLDocument;
+import javax.swing.text.html.HTMLEditorKit;
+import javax.swing.text.html.StyleSheet;
+import javax.swing.text.rtf.RTFEditorKit;
+import javax.swing.undo.UndoManager;
+import javax.swing.undo.CannotUndoException;
+
+import com.hexidec.ekit.action.*;
+import com.hexidec.ekit.component.*;
+import com.hexidec.util.Base64Codec;
+import com.hexidec.util.Translatrix;
+
+/** EkitCore
+  * Main application class for editing and saving HTML in a Java text component
+  *
+  * @author Howard Kistler
+  * @version 0.9g
+  *
+  * REQUIREMENTS
+  * Java 2 (JDK 1.3 or 1.4)
+  * Swing Library
+  */
+
+public class EkitCore extends JPanel implements ActionListener, KeyListener, DocumentListener
+{
+       /* Components */
+       private JSplitPane jspltDisplay;
+       private JTextPane jtpMain;
+       private ExtendedHTMLEditorKit htmlKit;
+       private ExtendedHTMLDocument htmlDoc;
+       private StyleSheet styleSheet;
+       private JTextPane jtpSource;
+       private JScrollPane jspSource;
+       private JToolBar jToolBar;
+
+       private JCheckBoxMenuItem jcbmiViewToolbar;
+       private JCheckBoxMenuItem jcbmiViewSource;
+
+       private JButtonNoFocus jbtnNewHTML;
+       private JButtonNoFocus jbtnOpenHTML;
+       private JButtonNoFocus jbtnSaveHTML;
+       private JButtonNoFocus jbtnCut;
+       private JButtonNoFocus jbtnCopy;
+       private JButtonNoFocus jbtnPaste;
+       private JButtonNoFocus jbtnBold;
+       private JButtonNoFocus jbtnItalic;
+       private JButtonNoFocus jbtnUnderline;
+       private JButtonNoFocus jbtnStrike;
+       private JButtonNoFocus jbtnSuperscript;
+       private JButtonNoFocus jbtnSubscript;
+       private JButtonNoFocus jbtnUList;
+       private JButtonNoFocus jbtnOList;
+       private JButtonNoFocus jbtnClearFormat;
+       private JButtonNoFocus jbtnAnchor;
+       private JToggleButtonNoFocus jtbtnViewSource;
+       private JComboBoxNoFocus jcmbStyleSelector;
+
+       private Frame frameHandler;
+
+       private HTMLUtilities htmlUtilities = new HTMLUtilities(this);
+
+       /* Actions */
+       private StyledEditorKit.BoldAction actionFontBold;
+       private StyledEditorKit.ItalicAction actionFontItalic;
+       private StyledEditorKit.UnderlineAction actionFontUnderline;
+       private FormatAction actionFontStrike;
+       private FormatAction actionFontSuperscript;
+       private FormatAction actionFontSubscript;
+       private ListAutomationAction actionListUnordered;
+       private ListAutomationAction actionListOrdered;
+       private CustomAction actionSelectFont;
+       private CustomAction actionClearFormat;
+       private CustomAction actionInsertAnchor;
+
+       protected UndoManager undoMngr;
+       protected UndoAction undoAction;
+       protected RedoAction redoAction;
+
+       /* Menus */
+       private JMenuBar jMenuBar;
+       private JMenu jMenuFile;
+       private JMenu jMenuEdit;
+       private JMenu jMenuView;
+       private JMenu jMenuFont;
+       private JMenu jMenuFormat;
+       private JMenu jMenuInsert;
+       private JMenu jMenuTable;
+       private JMenu jMenuForms;
+       private JMenu jMenuSearch;
+       private JMenu jMenuHelp;
+       private JMenu jMenuDebug;
+
+       /* Constants */
+       // Menu Keys
+       public static final String KEY_MENU_FILE   = "file";
+       public static final String KEY_MENU_EDIT   = "edit";
+       public static final String KEY_MENU_VIEW   = "view";
+       public static final String KEY_MENU_FONT   = "font";
+       public static final String KEY_MENU_FORMAT = "format";
+       public static final String KEY_MENU_INSERT = "insert";
+       public static final String KEY_MENU_TABLE  = "table";
+       public static final String KEY_MENU_FORMS  = "forms";
+       public static final String KEY_MENU_SEARCH = "search";
+       public static final String KEY_MENU_TOOLS  = "tools";
+       public static final String KEY_MENU_HELP   = "help";
+       public static final String KEY_MENU_DEBUG  = "debug";
+
+       // Tool Keys
+       public static final String KEY_TOOL_SEP       = "separator";
+       public static final String KEY_TOOL_NEW       = "new";
+       public static final String KEY_TOOL_OPEN      = "open";
+       public static final String KEY_TOOL_SAVE      = "save";
+       public static final String KEY_TOOL_CUT       = "cut";
+       public static final String KEY_TOOL_COPY      = "copy";
+       public static final String KEY_TOOL_PASTE     = "paste";
+       public static final String KEY_TOOL_BOLD      = "bold";
+       public static final String KEY_TOOL_ITALIC    = "italic";
+       public static final String KEY_TOOL_UNDERLINE = "underline";
+       public static final String KEY_TOOL_STRIKE    = "strike";
+       public static final String KEY_TOOL_SUPER     = "superscript";
+       public static final String KEY_TOOL_SUB       = "subscript";
+       public static final String KEY_TOOL_ULIST     = "ulist";
+       public static final String KEY_TOOL_OLIST     = "olist";
+       public static final String KEY_TOOL_CLEAR     = "clearformats";
+       public static final String KEY_TOOL_ANCHOR    = "anchor";
+       public static final String KEY_TOOL_SOURCE    = "viewsource";
+       public static final String KEY_TOOL_STYLES    = "styleselect";
+
+       // Menu & Tool Key Arrays
+       private static Hashtable htMenus = new Hashtable();
+       private static Hashtable htTools = new Hashtable();
+
+       private final String appName = "Ekit";
+       private final String menuDialog = "..."; /* text to append to a MenuItem label when menu item opens a dialog */
+
+       private final boolean useFormIndicator = true; /* Creates a highlighted background on a new FORM so that it may be more easily edited */
+       private final String clrFormIndicator = "#cccccc";
+
+       // System Clipboard Settings
+       private java.awt.datatransfer.Clipboard sysClipboard;
+       private SecurityManager secManager;
+
+       /* Variables */
+       private int iSplitPos = 0;
+
+       private boolean exclusiveEdit = true;
+
+       private String lastSearchFindTerm     = null;
+       private String lastSearchReplaceTerm  = null;
+       private boolean lastSearchCaseSetting = false;
+       private boolean lastSearchTopSetting  = false;
+
+       private File currentFile = null;
+
+       private int indent = 0;
+       private final int indentStep = 4;
+
+       // File extensions for MutableFilter
+       private final String[] extsHTML = { "html", "htm", "shtml" };
+       private final String[] extsCSS  = { "css" };
+       private final String[] extsIMG  = { "gif", "jpg", "jpeg", "png" };
+       private final String[] extsRTF  = { "rtf" };
+       private final String[] extsB64  = { "b64" };
+       private final String[] extsSer  = { "ser" };
+
+       /* Servlet Settings */
+       private String ServletURL = null;
+       private String TreePilotSystemID = "";
+       private String ImageDir = "";
+       private static ResourceBundle TreePilotProperties;
+
+       /** Master Constructor
+         * @param sDocument         [String]  A text or HTML document to load in the editor upon startup.
+         * @param sStyleSheet       [String]  A CSS stylesheet to load in the editor upon startup.
+         * @param sRawDocument      [String]  A document encoded as a String to load in the editor upon startup.
+         * @param urlStyleSheet     [URL]     A URL reference to the CSS style sheet.
+         * @param showViewSource    [boolean] Specifies whether or not to show the View Source window on startup.
+         * @param showMenuIcons     [boolean] Specifies whether or not to show icon pictures in menus.
+         * @param editModeExclusive [boolean] Specifies whether or not to use exclusive edit mode (recommended on).
+         * @param sLanguage         [String]  The language portion of the Internationalization Locale to run Ekit in.
+         * @param sCountry          [String]  The country portion of the Internationalization Locale to run Ekit in.
+         * @param base64            [boolean] Specifies whether the raw document is Base64 encoded or not.
+         * @param debugMode         [boolean] Specifies whether to show the Debug menu or not.
+         */
+       public EkitCore(String sDocument, String sStyleSheet, String sRawDocument, URL urlStyleSheet, boolean showViewSource, boolean showMenuIcons, boolean editModeExclusive, String sLanguage, String sCountry, boolean base64, boolean debugMode)
+       {
+               super();
+
+               exclusiveEdit = editModeExclusive;
+
+               frameHandler = new Frame();
+
+               // Determine if system clipboard is available
+               secManager = System.getSecurityManager();
+               if(secManager != null)
+               {
+                       try
+                       {
+                               secManager.checkSystemClipboardAccess();
+                               sysClipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
+                       }
+                       catch (SecurityException se)
+                       {
+                               sysClipboard = null;
+                       }
+               }
+
+               /* Localize for language */
+               Translatrix.setBundleName("com.hexidec.ekit.LanguageResources");
+               Locale baseLocale = (Locale)null;
+               if(sLanguage != null && sCountry != null)
+               {
+                       baseLocale = new Locale(sLanguage, sCountry);
+               }
+               Translatrix.setLocale(baseLocale);
+
+               /* Load TreePilot properties */
+               try
+               {
+                       TreePilotProperties = ResourceBundle.getBundle("com.hexidec.ekit.TreePilot");
+               }
+               catch(MissingResourceException mre)
+               {
+                       logException("MissingResourceException while loading treepilot file", mre);
+               }
+
+               /* Create the editor kit, document, and stylesheet */
+               jtpMain = new JTextPane();
+               htmlKit = new ExtendedHTMLEditorKit();
+               htmlDoc = (ExtendedHTMLDocument)(htmlKit.createDefaultDocument());
+               styleSheet = htmlDoc.getStyleSheet();
+               htmlKit.setDefaultCursor(new Cursor(Cursor.TEXT_CURSOR));
+
+               /* Set up the text pane */
+               jtpMain.setEditorKit(htmlKit);
+               jtpMain.setDocument(htmlDoc);
+               jtpMain.setMargin(new Insets(4, 4, 4, 4));
+               jtpMain.addKeyListener(this);
+
+               /* Create the source text area */
+               jtpSource = new JTextPane();
+               jtpSource.setBackground(new Color(212, 212, 212));
+               jtpSource.setSelectionColor(new Color(255, 192, 192));
+               jtpSource.setText(jtpMain.getText());
+               jtpSource.getDocument().addDocumentListener(this);
+
+               /* Add CaretListener for tracking caret location events */
+               jtpMain.addCaretListener(new CaretListener()
+               {
+                       public void caretUpdate(CaretEvent ce)
+                       {
+                               handleCaretPositionChange(ce);
+                       }
+               });
+
+               /* Set up the undo features */
+               undoMngr = new UndoManager();
+               undoAction = new UndoAction();
+               redoAction = new RedoAction();
+               jtpMain.getDocument().addUndoableEditListener(new CustomUndoableEditListener());
+
+               /* Insert raw document, if exists */
+               if(sRawDocument != null && sRawDocument.length() > 0)
+               {
+                       if(base64)
+                       {
+                               jtpMain.setText(Base64Codec.decode(sRawDocument));
+                       }
+                       else
+                       {
+                               jtpMain.setText(sRawDocument);
+                       }
+               }
+               jtpMain.setCaretPosition(0);
+               jtpMain.getDocument().addDocumentListener(this);
+
+               /* Import CSS from reference, if exists */
+               if(urlStyleSheet != null)
+               {
+                       try
+                       {
+                               String currDocText = jtpMain.getText();
+                               htmlDoc = (ExtendedHTMLDocument)(htmlKit.createDefaultDocument());
+                               styleSheet = htmlDoc.getStyleSheet();
+                               BufferedReader br = new BufferedReader(new InputStreamReader(urlStyleSheet.openStream()));
+                               styleSheet.loadRules(br, urlStyleSheet);
+                               br.close();
+                               htmlDoc = new ExtendedHTMLDocument(styleSheet);
+                               registerDocument(htmlDoc);
+                               jtpMain.setText(currDocText);
+                               jtpSource.setText(jtpMain.getText());
+                       }
+                       catch(Exception e)
+                       {
+                               e.printStackTrace(System.out);
+                       }
+               }
+
+               /* Preload the specified HTML document, if exists */
+               if(sDocument != null)
+               {
+                       File defHTML = new File(sDocument);
+                       if(defHTML.exists())
+                       {
+                               try
+                               {
+                                       openDocument(defHTML);
+                               }
+                               catch(Exception e)
+                               {
+                                       logException("Exception in preloading HTML document", e);
+                               }
+                       }
+               }
+
+               /* Preload the specified CSS document, if exists */
+               if(sStyleSheet != null)
+               {
+                       File defCSS = new File(sStyleSheet);
+                       if(defCSS.exists())
+                       {
+                               try
+                               {
+                                       openStyleSheet(defCSS);
+                               }
+                               catch(Exception e)
+                               {
+                                       logException("Exception in preloading CSS stylesheet", e);
+                               }
+                       }
+               }
+
+               /* Collect the actions that the JTextPane is naturally aware of */
+               Hashtable actions = new Hashtable();
+               Action[] actionsArray = jtpMain.getActions();
+               for(int i = 0; i < actionsArray.length; i++)
+               {
+                       Action a = actionsArray[i];
+                       actions.put(a.getValue(Action.NAME), a);
+               }
+
+               /* Create shared actions */
+               actionFontBold        = new StyledEditorKit.BoldAction();
+               actionFontItalic      = new StyledEditorKit.ItalicAction();
+               actionFontUnderline   = new StyledEditorKit.UnderlineAction();
+               actionFontStrike      = new FormatAction(this, Translatrix.getTranslationString("FontStrike"), HTML.Tag.STRIKE);
+               actionFontSuperscript = new FormatAction(this, Translatrix.getTranslationString("FontSuperscript"), HTML.Tag.SUP);
+               actionFontSubscript   = new FormatAction(this, Translatrix.getTranslationString("FontSubscript"), HTML.Tag.SUB);
+               actionListUnordered   = new ListAutomationAction(this, Translatrix.getTranslationString("ListUnordered"), HTML.Tag.UL);
+               actionListOrdered     = new ListAutomationAction(this, Translatrix.getTranslationString("ListOrdered"), HTML.Tag.OL);
+               Hashtable customAttr = new Hashtable();
+               customAttr.put("face","");
+               actionSelectFont      = new CustomAction(this, Translatrix.getTranslationString("FontSelect") + menuDialog, HTML.Tag.FONT, customAttr);
+               actionClearFormat     = new CustomAction(this, Translatrix.getTranslationString("FormatClear"), new HTML.UnknownTag(""));
+               actionInsertAnchor    = new CustomAction(this, Translatrix.getTranslationString("InsertAnchor") + menuDialog, HTML.Tag.A);
+
+               /* Build the menus */
+               /* FILE Menu */
+               jMenuFile              = new JMenu(Translatrix.getTranslationString("File"));
+               htMenus.put(KEY_MENU_FILE, jMenuFile);
+               JMenuItem jmiNew       = new JMenuItem(Translatrix.getTranslationString("NewDocument"));                     jmiNew.setActionCommand("newdoc");        jmiNew.addActionListener(this);      jmiNew.setAccelerator(KeyStroke.getKeyStroke('N', java.awt.Event.CTRL_MASK, false));      if(showMenuIcons) { jmiNew.setIcon(getEkitIcon("New")); }; jMenuFile.add(jmiNew);
+               JMenuItem jmiOpenHTML  = new JMenuItem(Translatrix.getTranslationString("OpenDocument") + menuDialog);       jmiOpenHTML.setActionCommand("openhtml"); jmiOpenHTML.addActionListener(this); jmiOpenHTML.setAccelerator(KeyStroke.getKeyStroke('O', java.awt.Event.CTRL_MASK, false)); if(showMenuIcons) { jmiOpenHTML.setIcon(getEkitIcon("Open")); }; jMenuFile.add(jmiOpenHTML);
+               JMenuItem jmiOpenCSS   = new JMenuItem(Translatrix.getTranslationString("OpenStyle") + menuDialog);          jmiOpenCSS.setActionCommand("opencss");   jmiOpenCSS.addActionListener(this);  jMenuFile.add(jmiOpenCSS);
+               JMenuItem jmiOpenB64   = new JMenuItem(Translatrix.getTranslationString("OpenBase64Document") + menuDialog); jmiOpenB64.setActionCommand("openb64");   jmiOpenB64.addActionListener(this);  jMenuFile.add(jmiOpenB64);
+               jMenuFile.addSeparator();
+               JMenuItem jmiSave      = new JMenuItem(Translatrix.getTranslationString("Save"));                  jmiSave.setActionCommand("save");         jmiSave.addActionListener(this);     jmiSave.setAccelerator(KeyStroke.getKeyStroke('S', java.awt.Event.CTRL_MASK, false)); if(showMenuIcons) { jmiSave.setIcon(getEkitIcon("Save")); }; jMenuFile.add(jmiSave);
+               JMenuItem jmiSaveAs    = new JMenuItem(Translatrix.getTranslationString("SaveAs") + menuDialog);   jmiSaveAs.setActionCommand("saveas");     jmiSaveAs.addActionListener(this);   jMenuFile.add(jmiSaveAs);
+               JMenuItem jmiSaveBody  = new JMenuItem(Translatrix.getTranslationString("SaveBody") + menuDialog); jmiSaveBody.setActionCommand("savebody"); jmiSaveBody.addActionListener(this); jMenuFile.add(jmiSaveBody);
+               JMenuItem jmiSaveRTF   = new JMenuItem(Translatrix.getTranslationString("SaveRTF") + menuDialog);  jmiSaveRTF.setActionCommand("savertf");   jmiSaveRTF.addActionListener(this);  jMenuFile.add(jmiSaveRTF);
+               JMenuItem jmiSaveB64   = new JMenuItem(Translatrix.getTranslationString("SaveB64") + menuDialog);  jmiSaveB64.setActionCommand("saveb64");   jmiSaveB64.addActionListener(this);  jMenuFile.add(jmiSaveB64);
+               jMenuFile.addSeparator();
+               JMenuItem jmiSerialOut = new JMenuItem(Translatrix.getTranslationString("Serialize") + menuDialog);   jmiSerialOut.setActionCommand("serialize");  jmiSerialOut.addActionListener(this); jMenuFile.add(jmiSerialOut);
+               JMenuItem jmiSerialIn  = new JMenuItem(Translatrix.getTranslationString("ReadFromSer") + menuDialog); jmiSerialIn.setActionCommand("readfromser"); jmiSerialIn.addActionListener(this);  jMenuFile.add(jmiSerialIn);
+               jMenuFile.addSeparator();
+               JMenuItem jmiExit      = new JMenuItem(Translatrix.getTranslationString("Exit")); jmiExit.setActionCommand("exit"); jmiExit.addActionListener(this); jMenuFile.add(jmiExit);
+
+               /* EDIT Menu */
+               jMenuEdit            = new JMenu(Translatrix.getTranslationString("Edit"));
+               htMenus.put(KEY_MENU_EDIT, jMenuEdit);
+               if(sysClipboard != null)
+               {
+                       // System Clipboard versions of menu commands
+                       JMenuItem jmiCut     = new JMenuItem(Translatrix.getTranslationString("Cut"));   jmiCut.setActionCommand("textcut");     jmiCut.addActionListener(this);   jmiCut.setAccelerator(KeyStroke.getKeyStroke('X', java.awt.Event.CTRL_MASK, false));   if(showMenuIcons) { jmiCut.setIcon(getEkitIcon("Cut")); }     jMenuEdit.add(jmiCut);
+                       JMenuItem jmiCopy    = new JMenuItem(Translatrix.getTranslationString("Copy"));  jmiCopy.setActionCommand("textcopy");   jmiCopy.addActionListener(this);  jmiCopy.setAccelerator(KeyStroke.getKeyStroke('C', java.awt.Event.CTRL_MASK, false));  if(showMenuIcons) { jmiCopy.setIcon(getEkitIcon("Copy")); }   jMenuEdit.add(jmiCopy);
+                       JMenuItem jmiPaste   = new JMenuItem(Translatrix.getTranslationString("Paste")); jmiPaste.setActionCommand("textpaste"); jmiPaste.addActionListener(this); jmiPaste.setAccelerator(KeyStroke.getKeyStroke('V', java.awt.Event.CTRL_MASK, false)); if(showMenuIcons) { jmiPaste.setIcon(getEkitIcon("Paste")); } jMenuEdit.add(jmiPaste);
+               }
+               else
+               {
+                       // DefaultEditorKit versions of menu commands
+                       JMenuItem jmiCut     = new JMenuItem(new DefaultEditorKit.CutAction());   jmiCut.setText(Translatrix.getTranslationString("Cut"));     jmiCut.setAccelerator(KeyStroke.getKeyStroke('X', java.awt.Event.CTRL_MASK, false));   if(showMenuIcons) { jmiCut.setIcon(getEkitIcon("Cut")); }     jMenuEdit.add(jmiCut);
+                       JMenuItem jmiCopy    = new JMenuItem(new DefaultEditorKit.CopyAction());  jmiCopy.setText(Translatrix.getTranslationString("Copy"));   jmiCopy.setAccelerator(KeyStroke.getKeyStroke('C', java.awt.Event.CTRL_MASK, false));  if(showMenuIcons) { jmiCopy.setIcon(getEkitIcon("Copy")); }   jMenuEdit.add(jmiCopy);
+                       JMenuItem jmiPaste   = new JMenuItem(new DefaultEditorKit.PasteAction()); jmiPaste.setText(Translatrix.getTranslationString("Paste")); jmiPaste.setAccelerator(KeyStroke.getKeyStroke('V', java.awt.Event.CTRL_MASK, false)); if(showMenuIcons) { jmiPaste.setIcon(getEkitIcon("Paste")); } jMenuEdit.add(jmiPaste);
+               }
+               jMenuEdit.addSeparator();
+               JMenuItem jmiUndo    = new JMenuItem(undoAction); jmiUndo.setAccelerator(KeyStroke.getKeyStroke('Z', java.awt.Event.CTRL_MASK, false)); jMenuEdit.add(jmiUndo);
+               JMenuItem jmiRedo    = new JMenuItem(redoAction); jmiRedo.setAccelerator(KeyStroke.getKeyStroke('Y', java.awt.Event.CTRL_MASK, false)); jMenuEdit.add(jmiRedo);
+               jMenuEdit.addSeparator();
+               JMenuItem jmiSelAll  = new JMenuItem((Action)actions.get(DefaultEditorKit.selectAllAction));       jmiSelAll.setText(Translatrix.getTranslationString("SelectAll"));        jmiSelAll.setAccelerator(KeyStroke.getKeyStroke('A', java.awt.Event.CTRL_MASK, false)); jMenuEdit.add(jmiSelAll);
+               JMenuItem jmiSelPara = new JMenuItem((Action)actions.get(DefaultEditorKit.selectParagraphAction)); jmiSelPara.setText(Translatrix.getTranslationString("SelectParagraph")); jMenuEdit.add(jmiSelPara);
+               JMenuItem jmiSelLine = new JMenuItem((Action)actions.get(DefaultEditorKit.selectLineAction));      jmiSelLine.setText(Translatrix.getTranslationString("SelectLine"));      jMenuEdit.add(jmiSelLine);
+               JMenuItem jmiSelWord = new JMenuItem((Action)actions.get(DefaultEditorKit.selectWordAction));      jmiSelWord.setText(Translatrix.getTranslationString("SelectWord"));      jMenuEdit.add(jmiSelWord);
+
+               /* VIEW Menu */
+               jMenuView        = new JMenu(Translatrix.getTranslationString("View"));
+               htMenus.put(KEY_MENU_VIEW, jMenuView);
+               jcbmiViewToolbar = new JCheckBoxMenuItem(Translatrix.getTranslationString("ViewToolbar"), false); jcbmiViewToolbar.setActionCommand("toggletoolbar"); jcbmiViewToolbar.addActionListener(this); jMenuView.add(jcbmiViewToolbar);
+               jcbmiViewSource  = new JCheckBoxMenuItem(Translatrix.getTranslationString("ViewSource"), false);  jcbmiViewSource.setActionCommand("viewsource");     jcbmiViewSource.addActionListener(this);  jMenuView.add(jcbmiViewSource);
+
+               /* FONT Menu */
+               jMenuFont              = new JMenu(Translatrix.getTranslationString("Font"));
+               htMenus.put(KEY_MENU_FONT, jMenuFont);
+               JMenuItem jmiBold      = new JMenuItem(actionFontBold);      jmiBold.setText(Translatrix.getTranslationString("FontBold"));           jmiBold.setAccelerator(KeyStroke.getKeyStroke('B', java.awt.Event.CTRL_MASK, false));      if(showMenuIcons) { jmiBold.setIcon(getEkitIcon("Bold")); }           jMenuFont.add(jmiBold);
+               JMenuItem jmiItalic    = new JMenuItem(actionFontItalic);    jmiItalic.setText(Translatrix.getTranslationString("FontItalic"));       jmiItalic.setAccelerator(KeyStroke.getKeyStroke('I', java.awt.Event.CTRL_MASK, false));    if(showMenuIcons) { jmiItalic.setIcon(getEkitIcon("Italic")); }       jMenuFont.add(jmiItalic);
+               JMenuItem jmiUnderline = new JMenuItem(actionFontUnderline); jmiUnderline.setText(Translatrix.getTranslationString("FontUnderline")); jmiUnderline.setAccelerator(KeyStroke.getKeyStroke('U', java.awt.Event.CTRL_MASK, false)); if(showMenuIcons) { jmiUnderline.setIcon(getEkitIcon("Underline")); } jMenuFont.add(jmiUnderline);
+               JMenuItem jmiStrike    = new JMenuItem(actionFontStrike);    jmiStrike.setText(Translatrix.getTranslationString("FontStrike"));                                                                                                  if(showMenuIcons) { jmiStrike.setIcon(getEkitIcon("Strike")); }       jMenuFont.add(jmiStrike);
+               jMenuFont.addSeparator();
+               jMenuFont.add(new JMenuItem(new FormatAction(this, Translatrix.getTranslationString("FormatBig"), HTML.Tag.BIG)));
+               jMenuFont.add(new JMenuItem(new FormatAction(this, Translatrix.getTranslationString("FormatSmall"), HTML.Tag.SMALL)));
+               JMenu jMenuFontSize = new JMenu(Translatrix.getTranslationString("FontSize"));
+                       String fontSizeKey = "size";
+                       customAttr = new Hashtable(); customAttr.put(fontSizeKey,"1");
+                       jMenuFontSize.add(new JMenuItem(new CustomAction(this, Translatrix.getTranslationString("FontSize1"), HTML.Tag.FONT, customAttr)));
+                       customAttr = new Hashtable(); customAttr.put(fontSizeKey,"2");
+                       jMenuFontSize.add(new JMenuItem(new CustomAction(this, Translatrix.getTranslationString("FontSize2"), HTML.Tag.FONT, customAttr)));
+                       customAttr = new Hashtable(); customAttr.put(fontSizeKey,"3");
+                       jMenuFontSize.add(new JMenuItem(new CustomAction(this, Translatrix.getTranslationString("FontSize3"), HTML.Tag.FONT, customAttr)));
+                       customAttr = new Hashtable(); customAttr.put(fontSizeKey,"4");
+                       jMenuFontSize.add(new JMenuItem(new CustomAction(this, Translatrix.getTranslationString("FontSize4"), HTML.Tag.FONT, customAttr)));
+                       customAttr = new Hashtable(); customAttr.put(fontSizeKey,"5");
+                       jMenuFontSize.add(new JMenuItem(new CustomAction(this, Translatrix.getTranslationString("FontSize5"), HTML.Tag.FONT, customAttr)));
+                       customAttr = new Hashtable(); customAttr.put(fontSizeKey,"6");
+                       jMenuFontSize.add(new JMenuItem(new CustomAction(this, Translatrix.getTranslationString("FontSize6"), HTML.Tag.FONT, customAttr)));
+                       customAttr = new Hashtable(); customAttr.put(fontSizeKey,"7");
+                       jMenuFontSize.add(new JMenuItem(new CustomAction(this, Translatrix.getTranslationString("FontSize7"), HTML.Tag.FONT, customAttr)));
+               jMenuFont.add(jMenuFontSize);
+               jMenuFont.addSeparator();
+               JMenuItem jmiSupscript = new JMenuItem(actionFontSuperscript); if(showMenuIcons) { jmiSupscript.setIcon(getEkitIcon("Super")); } jMenuFont.add(jmiSupscript);
+               JMenuItem jmiSubscript = new JMenuItem(actionFontSubscript);   if(showMenuIcons) { jmiSubscript.setIcon(getEkitIcon("Sub")); }   jMenuFont.add(jmiSubscript);
+               jMenuFont.addSeparator();
+               JMenuItem jmiSerif      = new JMenuItem((Action)actions.get("font-family-Serif"));      jmiSerif.setText(Translatrix.getTranslationString("FontSerif"));           jMenuFont.add(jmiSerif);
+               JMenuItem jmiSansSerif  = new JMenuItem((Action)actions.get("font-family-SansSerif"));  jmiSansSerif.setText(Translatrix.getTranslationString("FontSansserif"));   jMenuFont.add(jmiSansSerif);
+               JMenuItem jmiMonospaced = new JMenuItem((Action)actions.get("font-family-Monospaced")); jmiMonospaced.setText(Translatrix.getTranslationString("FontMonospaced")); jMenuFont.add(jmiMonospaced);
+               JMenuItem jmiSelectFont = new JMenuItem(actionSelectFont);                                                                                                         jMenuFont.add(jmiSelectFont);
+               jMenuFont.addSeparator();
+               JMenu jMenuFontColor = new JMenu(Translatrix.getTranslationString("Color"));
+                       customAttr = new Hashtable(); customAttr.put("color","black");
+                       jMenuFontColor.add(new JMenuItem(new CustomAction(this, Translatrix.getTranslationString("CustomColor") + menuDialog, HTML.Tag.FONT, customAttr)));
+                       jMenuFontColor.add(new JMenuItem(new StyledEditorKit.ForegroundAction(Translatrix.getTranslationString("ColorAqua"),    new Color(  0,255,255))));
+                       jMenuFontColor.add(new JMenuItem(new StyledEditorKit.ForegroundAction(Translatrix.getTranslationString("ColorBlack"),   new Color(  0,  0,  0))));
+                       jMenuFontColor.add(new JMenuItem(new StyledEditorKit.ForegroundAction(Translatrix.getTranslationString("ColorBlue"),    new Color(  0,  0,255))));
+                       jMenuFontColor.add(new JMenuItem(new StyledEditorKit.ForegroundAction(Translatrix.getTranslationString("ColorFuschia"), new Color(255,  0,255))));
+                       jMenuFontColor.add(new JMenuItem(new StyledEditorKit.ForegroundAction(Translatrix.getTranslationString("ColorGray"),    new Color(128,128,128))));
+                       jMenuFontColor.add(new JMenuItem(new StyledEditorKit.ForegroundAction(Translatrix.getTranslationString("ColorGreen"),   new Color(  0,128,  0))));
+                       jMenuFontColor.add(new JMenuItem(new StyledEditorKit.ForegroundAction(Translatrix.getTranslationString("ColorLime"),    new Color(  0,255,  0))));
+                       jMenuFontColor.add(new JMenuItem(new StyledEditorKit.ForegroundAction(Translatrix.getTranslationString("ColorMaroon"),  new Color(128,  0,  0))));
+                       jMenuFontColor.add(new JMenuItem(new StyledEditorKit.ForegroundAction(Translatrix.getTranslationString("ColorNavy"),    new Color(  0,  0,128))));
+                       jMenuFontColor.add(new JMenuItem(new StyledEditorKit.ForegroundAction(Translatrix.getTranslationString("ColorOlive"),   new Color(128,128,  0))));
+                       jMenuFontColor.add(new JMenuItem(new StyledEditorKit.ForegroundAction(Translatrix.getTranslationString("ColorPurple"),  new Color(128,  0,128))));
+                       jMenuFontColor.add(new JMenuItem(new StyledEditorKit.ForegroundAction(Translatrix.getTranslationString("ColorRed"),     new Color(255,  0,  0))));
+                       jMenuFontColor.add(new JMenuItem(new StyledEditorKit.ForegroundAction(Translatrix.getTranslationString("ColorSilver"),  new Color(192,192,192))));
+                       jMenuFontColor.add(new JMenuItem(new StyledEditorKit.ForegroundAction(Translatrix.getTranslationString("ColorTeal"),    new Color(  0,128,128))));
+                       jMenuFontColor.add(new JMenuItem(new StyledEditorKit.ForegroundAction(Translatrix.getTranslationString("ColorWhite"),   new Color(255,255,255))));
+                       jMenuFontColor.add(new JMenuItem(new StyledEditorKit.ForegroundAction(Translatrix.getTranslationString("ColorYellow"),  new Color(255,255,  0))));
+               jMenuFont.add(jMenuFontColor);
+
+               /* FORMAT Menu */
+               jMenuFormat            = new JMenu(Translatrix.getTranslationString("Format"));
+               htMenus.put(KEY_MENU_FORMAT, jMenuFormat);
+               JMenu jMenuFormatAlign = new JMenu(Translatrix.getTranslationString("Align"));
+                       jMenuFormatAlign.add(new JMenuItem(new StyledEditorKit.AlignmentAction(Translatrix.getTranslationString("AlignLeft"), StyleConstants.ALIGN_LEFT)));
+                       jMenuFormatAlign.add(new JMenuItem(new StyledEditorKit.AlignmentAction(Translatrix.getTranslationString("AlignCenter"), StyleConstants.ALIGN_CENTER)));
+                       jMenuFormatAlign.add(new JMenuItem(new StyledEditorKit.AlignmentAction(Translatrix.getTranslationString("AlignRight"), StyleConstants.ALIGN_RIGHT)));
+                       jMenuFormatAlign.add(new JMenuItem(new StyledEditorKit.AlignmentAction(Translatrix.getTranslationString("AlignJustified"), StyleConstants.ALIGN_JUSTIFIED)));
+               jMenuFormat.add(jMenuFormatAlign);
+               jMenuFormat.addSeparator();
+               JMenu jMenuFormatHeading = new JMenu(Translatrix.getTranslationString("Heading"));
+                       jMenuFormatHeading.add(new JMenuItem(new FormatAction(this, Translatrix.getTranslationString("Heading1"), HTML.Tag.H1)));
+                       jMenuFormatHeading.add(new JMenuItem(new FormatAction(this, Translatrix.getTranslationString("Heading2"), HTML.Tag.H2)));
+                       jMenuFormatHeading.add(new JMenuItem(new FormatAction(this, Translatrix.getTranslationString("Heading3"), HTML.Tag.H3)));
+                       jMenuFormatHeading.add(new JMenuItem(new FormatAction(this, Translatrix.getTranslationString("Heading4"), HTML.Tag.H4)));
+                       jMenuFormatHeading.add(new JMenuItem(new FormatAction(this, Translatrix.getTranslationString("Heading5"), HTML.Tag.H5)));
+                       jMenuFormatHeading.add(new JMenuItem(new FormatAction(this, Translatrix.getTranslationString("Heading6"), HTML.Tag.H6)));
+               jMenuFormat.add(jMenuFormatHeading);
+               jMenuFormat.addSeparator();
+               JMenuItem jmiUList = new JMenuItem(actionListUnordered); if(showMenuIcons) { jmiUList.setIcon(getEkitIcon("UList")); } jMenuFormat.add(jmiUList);
+               JMenuItem jmiOList = new JMenuItem(actionListOrdered);   if(showMenuIcons) { jmiOList.setIcon(getEkitIcon("OList")); } jMenuFormat.add(jmiOList);
+               jMenuFormat.add(new JMenuItem(new FormatAction(this, Translatrix.getTranslationString("ListItem"), HTML.Tag.LI)));
+               jMenuFormat.addSeparator();
+               jMenuFormat.add(new JMenuItem(new FormatAction(this, Translatrix.getTranslationString("FormatBlockquote"), HTML.Tag.BLOCKQUOTE)));
+               jMenuFormat.add(new JMenuItem(new FormatAction(this, Translatrix.getTranslationString("FormatPre"), HTML.Tag.PRE)));
+               jMenuFormat.add(new JMenuItem(new FormatAction(this, Translatrix.getTranslationString("FormatStrong"), HTML.Tag.STRONG)));
+               jMenuFormat.add(new JMenuItem(new FormatAction(this, Translatrix.getTranslationString("FormatEmphasis"), HTML.Tag.EM)));
+               jMenuFormat.add(new JMenuItem(new FormatAction(this, Translatrix.getTranslationString("FormatTT"), HTML.Tag.TT)));
+               jMenuFormat.add(new JMenuItem(new FormatAction(this, Translatrix.getTranslationString("FormatSpan"), HTML.Tag.SPAN)));
+               jMenuFormat.addSeparator();
+               JMenuItem jmiClearStyles = new JMenuItem(actionClearFormat); if(showMenuIcons) { jmiClearStyles.setIcon(getEkitIcon("ClearFormat")); }; jMenuFormat.add(jmiClearStyles);
+
+               /* INSERT Menu */
+               jMenuInsert              = new JMenu(Translatrix.getTranslationString("Insert"));
+               htMenus.put(KEY_MENU_INSERT, jMenuInsert);
+               jMenuInsert.add(new JMenuItem(actionInsertAnchor));
+               JMenuItem jmiBreak       = new JMenuItem(Translatrix.getTranslationString("InsertBreak"));                    jmiBreak.setActionCommand("insertbreak"); jmiBreak.addActionListener(this); jmiBreak.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, java.awt.Event.SHIFT_MASK, false)); jMenuInsert.add(jmiBreak);
+               JMenuItem jmiNBSP        = new JMenuItem(Translatrix.getTranslationString("InsertNBSP"));                     jmiNBSP.setActionCommand("insertnbsp");   jmiNBSP.addActionListener(this);  jMenuInsert.add(jmiNBSP);
+               JMenuItem jmiHRule       = new JMenuItem((Action)actions.get("InsertHR"));                                    jmiHRule.setText(Translatrix.getTranslationString("InsertHorizontalRule")); jMenuInsert.add(jmiHRule);
+               jMenuInsert.addSeparator();
+               JMenuItem jmiImageLocal  = new JMenuItem(Translatrix.getTranslationString("InsertLocalImage") + menuDialog);  jmiImageLocal.setActionCommand("insertlocalimage"); jmiImageLocal.addActionListener(this); jMenuInsert.add(jmiImageLocal);
+               JMenuItem jmiImageServer = new JMenuItem(Translatrix.getTranslationString("InsertServerImage") + menuDialog); jmiImageServer.setActionCommand("insertserverimage"); jmiImageServer.addActionListener(this); jMenuInsert.add(jmiImageServer);
+
+               /* TABLE Menu */
+               jMenuTable              = new JMenu(Translatrix.getTranslationString("Table"));
+               htMenus.put(KEY_MENU_TABLE, jMenuTable);
+               JMenuItem jmiTable       = new JMenuItem(Translatrix.getTranslationString("InsertTable") + menuDialog); jmiTable.setActionCommand("inserttable");             jmiTable.addActionListener(this);       jMenuTable.add(jmiTable);
+               jMenuTable.addSeparator();
+               JMenuItem jmiTableRow    = new JMenuItem(Translatrix.getTranslationString("InsertTableRow"));           jmiTableRow.setActionCommand("inserttablerow");       jmiTableRow.addActionListener(this);    jMenuTable.add(jmiTableRow);
+               JMenuItem jmiTableCol    = new JMenuItem(Translatrix.getTranslationString("InsertTableColumn"));        jmiTableCol.setActionCommand("inserttablecolumn");    jmiTableCol.addActionListener(this);    jMenuTable.add(jmiTableCol);
+               jMenuTable.addSeparator();
+               JMenuItem jmiTableRowDel = new JMenuItem(Translatrix.getTranslationString("DeleteTableRow"));           jmiTableRowDel.setActionCommand("deletetablerow");    jmiTableRowDel.addActionListener(this); jMenuTable.add(jmiTableRowDel);
+               JMenuItem jmiTableColDel = new JMenuItem(Translatrix.getTranslationString("DeleteTableColumn"));        jmiTableColDel.setActionCommand("deletetablecolumn"); jmiTableColDel.addActionListener(this); jMenuTable.add(jmiTableColDel);
+
+               /* FORMS Menu */
+               jMenuForms                    = new JMenu(Translatrix.getTranslationString("Forms"));
+               htMenus.put(KEY_MENU_FORMS, jMenuForms);
+               JMenuItem jmiFormInsertForm   = new JMenuItem(Translatrix.getTranslationString("FormInsertForm")); jmiFormInsertForm.setActionCommand("insertform");     jmiFormInsertForm.addActionListener(this); jMenuForms.add(jmiFormInsertForm);
+               jMenuForms.addSeparator();
+               JMenuItem jmiFormTextfield    = new JMenuItem(Translatrix.getTranslationString("FormTextfield"));  jmiFormTextfield.setActionCommand("inserttextfield"); jmiFormTextfield.addActionListener(this);  jMenuForms.add(jmiFormTextfield);
+               JMenuItem jmiFormTextarea     = new JMenuItem(Translatrix.getTranslationString("FormTextarea"));   jmiFormTextarea.setActionCommand("inserttextarea");   jmiFormTextarea.addActionListener(this);   jMenuForms.add(jmiFormTextarea);
+               JMenuItem jmiFormCheckbox     = new JMenuItem(Translatrix.getTranslationString("FormCheckbox"));   jmiFormCheckbox.setActionCommand("insertcheckbox");   jmiFormCheckbox.addActionListener(this);   jMenuForms.add(jmiFormCheckbox);
+               JMenuItem jmiFormRadio        = new JMenuItem(Translatrix.getTranslationString("FormRadio"));      jmiFormRadio.setActionCommand("insertradiobutton");   jmiFormRadio.addActionListener(this);      jMenuForms.add(jmiFormRadio);
+               JMenuItem jmiFormPassword     = new JMenuItem(Translatrix.getTranslationString("FormPassword"));   jmiFormPassword.setActionCommand("insertpassword");   jmiFormPassword.addActionListener(this);   jMenuForms.add(jmiFormPassword);
+               jMenuForms.addSeparator();
+               JMenuItem jmiFormButton       = new JMenuItem(Translatrix.getTranslationString("FormButton"));       jmiFormButton.setActionCommand("insertbutton");             jmiFormButton.addActionListener(this);       jMenuForms.add(jmiFormButton);
+               JMenuItem jmiFormButtonSubmit = new JMenuItem(Translatrix.getTranslationString("FormButtonSubmit")); jmiFormButtonSubmit.setActionCommand("insertbuttonsubmit"); jmiFormButtonSubmit.addActionListener(this); jMenuForms.add(jmiFormButtonSubmit);
+               JMenuItem jmiFormButtonReset  = new JMenuItem(Translatrix.getTranslationString("FormButtonReset"));  jmiFormButtonReset.setActionCommand("insertbuttonreset");   jmiFormButtonReset.addActionListener(this);  jMenuForms.add(jmiFormButtonReset);
+
+               /* SEARCH Menu */
+               jMenuSearch            = new JMenu(Translatrix.getTranslationString("Search"));
+               htMenus.put(KEY_MENU_SEARCH, jMenuSearch);
+               JMenuItem jmiFind      = new JMenuItem(Translatrix.getTranslationString("SearchFind"));      jmiFind.setActionCommand("find");           jmiFind.addActionListener(this);      jmiFind.setAccelerator(KeyStroke.getKeyStroke('F', java.awt.Event.CTRL_MASK, false));      jMenuSearch.add(jmiFind);
+               JMenuItem jmiFindAgain = new JMenuItem(Translatrix.getTranslationString("SearchFindAgain")); jmiFindAgain.setActionCommand("findagain"); jmiFindAgain.addActionListener(this); jmiFindAgain.setAccelerator(KeyStroke.getKeyStroke('G', java.awt.Event.CTRL_MASK, false)); jMenuSearch.add(jmiFindAgain);
+               JMenuItem jmiReplace   = new JMenuItem(Translatrix.getTranslationString("SearchReplace"));   jmiReplace.setActionCommand("replace");     jmiReplace.addActionListener(this);   jmiReplace.setAccelerator(KeyStroke.getKeyStroke('R', java.awt.Event.CTRL_MASK, false));   jMenuSearch.add(jmiReplace);
+
+               /* HELP Menu */
+               jMenuHelp = new JMenu(Translatrix.getTranslationString("Help"));
+               htMenus.put(KEY_MENU_HELP, jMenuHelp);
+               JMenuItem jmiAbout = new JMenuItem(Translatrix.getTranslationString("About")); jmiAbout.setActionCommand("helpabout"); jmiAbout.addActionListener(this); jMenuHelp.add(jmiAbout);
+
+               /* DEBUG Menu */
+               jMenuDebug           = new JMenu(Translatrix.getTranslationString("Debug"));
+               htMenus.put(KEY_MENU_DEBUG, jMenuDebug);
+               JMenuItem jmiDesc    = new JMenuItem(Translatrix.getTranslationString("DescribeDoc")); jmiDesc.setActionCommand("describe");       jmiDesc.addActionListener(this);    jMenuDebug.add(jmiDesc);
+               JMenuItem jmiDescCSS = new JMenuItem(Translatrix.getTranslationString("DescribeCSS")); jmiDescCSS.setActionCommand("describecss"); jmiDescCSS.addActionListener(this); jMenuDebug.add(jmiDescCSS);
+               JMenuItem jmiTag     = new JMenuItem(Translatrix.getTranslationString("WhatTags"));    jmiTag.setActionCommand("whattags");        jmiTag.addActionListener(this);     jMenuDebug.add(jmiTag);
+
+               /* Create menubar and add menus */
+               jMenuBar = new JMenuBar();
+               jMenuBar.add(jMenuFile);
+               jMenuBar.add(jMenuEdit);
+               jMenuBar.add(jMenuView);
+               jMenuBar.add(jMenuFont);
+               jMenuBar.add(jMenuFormat);
+               jMenuBar.add(jMenuSearch);
+               jMenuBar.add(jMenuInsert);
+               jMenuBar.add(jMenuTable);
+               jMenuBar.add(jMenuForms);
+               jMenuBar.add(jMenuHelp);
+               if(debugMode)
+               {
+                       jMenuBar.add(jMenuDebug);
+               }
+
+               /* Create the toolbar */
+               jToolBar = new JToolBar(JToolBar.HORIZONTAL);
+               jToolBar.setFloatable(false);
+               jbtnNewHTML     = new JButtonNoFocus(getEkitIcon("New"));  jbtnNewHTML.setToolTipText(Translatrix.getTranslationString("NewDocument"));   jbtnNewHTML.setActionCommand("newdoc");    jbtnNewHTML.addActionListener(this);  jToolBar.add(jbtnNewHTML);  htTools.put(KEY_TOOL_NEW, jbtnNewHTML);
+               jbtnOpenHTML    = new JButtonNoFocus(getEkitIcon("Open")); jbtnOpenHTML.setToolTipText(Translatrix.getTranslationString("OpenDocument")); jbtnOpenHTML.setActionCommand("openhtml"); jbtnOpenHTML.addActionListener(this); jToolBar.add(jbtnOpenHTML); htTools.put(KEY_TOOL_OPEN, jbtnOpenHTML);
+               jbtnSaveHTML    = new JButtonNoFocus(getEkitIcon("Save")); jbtnSaveHTML.setToolTipText(Translatrix.getTranslationString("SaveDocument")); jbtnSaveHTML.setActionCommand("saveas");   jbtnSaveHTML.addActionListener(this); jToolBar.add(jbtnSaveHTML); htTools.put(KEY_TOOL_SAVE, jbtnSaveHTML);
+               jToolBar.add(new JToolBar.Separator());
+               jbtnCut         = new JButtonNoFocus(new DefaultEditorKit.CutAction());   jbtnCut.setIcon(getEkitIcon("Cut"));     jbtnCut.setText(null);   jbtnCut.setToolTipText(Translatrix.getTranslationString("Cut"));     jToolBar.add(jbtnCut);   htTools.put(KEY_TOOL_CUT, jbtnCut);
+               jbtnCopy        = new JButtonNoFocus(new DefaultEditorKit.CopyAction());  jbtnCopy.setIcon(getEkitIcon("Copy"));   jbtnCopy.setText(null);  jbtnCopy.setToolTipText(Translatrix.getTranslationString("Copy"));   jToolBar.add(jbtnCopy);  htTools.put(KEY_TOOL_COPY, jbtnCopy);
+               jbtnPaste       = new JButtonNoFocus(new DefaultEditorKit.PasteAction()); jbtnPaste.setIcon(getEkitIcon("Paste")); jbtnPaste.setText(null); jbtnPaste.setToolTipText(Translatrix.getTranslationString("Paste")); jToolBar.add(jbtnPaste); htTools.put(KEY_TOOL_PASTE, jbtnPaste);
+               jToolBar.add(new JToolBar.Separator());
+               jbtnBold        = new JButtonNoFocus(actionFontBold);        jbtnBold.setIcon(getEkitIcon("Bold"));               jbtnBold.setText(null);        jbtnBold.setToolTipText(Translatrix.getTranslationString("FontBold"));                 jToolBar.add(jbtnBold);        htTools.put(KEY_TOOL_BOLD, jbtnBold);
+               jbtnItalic      = new JButtonNoFocus(actionFontItalic);      jbtnItalic.setIcon(getEkitIcon("Italic"));           jbtnItalic.setText(null);      jbtnItalic.setToolTipText(Translatrix.getTranslationString("FontItalic"));             jToolBar.add(jbtnItalic);      htTools.put(KEY_TOOL_ITALIC, jbtnItalic);
+               jbtnUnderline   = new JButtonNoFocus(actionFontUnderline);   jbtnUnderline.setIcon(getEkitIcon("Underline"));     jbtnUnderline.setText(null);   jbtnUnderline.setToolTipText(Translatrix.getTranslationString("FontUnderline"));       jToolBar.add(jbtnUnderline);   htTools.put(KEY_TOOL_UNDERLINE, jbtnUnderline);
+               jbtnStrike      = new JButtonNoFocus(actionFontStrike);      jbtnStrike.setIcon(getEkitIcon("Strike"));           jbtnStrike.setText(null);      jbtnStrike.setToolTipText(Translatrix.getTranslationString("FontStrike"));             jToolBar.add(jbtnStrike);      htTools.put(KEY_TOOL_STRIKE, jbtnStrike);
+               jbtnSuperscript = new JButtonNoFocus(actionFontSuperscript); jbtnSuperscript.setIcon(getEkitIcon("Super"));       jbtnSuperscript.setText(null); jbtnSuperscript.setToolTipText(Translatrix.getTranslationString("FontSuperscript")); jToolBar.add(jbtnSuperscript);   htTools.put(KEY_TOOL_SUPER, jbtnSuperscript);
+               jbtnSubscript   = new JButtonNoFocus(actionFontSubscript);   jbtnSubscript.setIcon(getEkitIcon("Sub"));           jbtnSubscript.setText(null);   jbtnSubscript.setToolTipText(Translatrix.getTranslationString("FontSubscript"));     jToolBar.add(jbtnSubscript);     htTools.put(KEY_TOOL_SUB, jbtnSubscript);
+               jbtnUList       = new JButtonNoFocus(actionListUnordered);   jbtnUList.setIcon(getEkitIcon("UList"));             jbtnUList.setText(null);       jbtnUList.setToolTipText(Translatrix.getTranslationString("ListUnordered"));           jToolBar.add(jbtnUList);       htTools.put(KEY_TOOL_ULIST, jbtnUList);
+               jbtnOList       = new JButtonNoFocus(actionListOrdered);     jbtnOList.setIcon(getEkitIcon("OList"));             jbtnOList.setText(null);       jbtnOList.setToolTipText(Translatrix.getTranslationString("ListOrdered"));             jToolBar.add(jbtnOList);       htTools.put(KEY_TOOL_OLIST, jbtnOList);
+               jbtnClearFormat = new JButtonNoFocus(actionClearFormat);     jbtnClearFormat.setIcon(getEkitIcon("ClearFormat")); jbtnClearFormat.setText(null); jbtnClearFormat.setToolTipText(Translatrix.getTranslationString("FormatClear"));       jToolBar.add(jbtnClearFormat); htTools.put(KEY_TOOL_CLEAR, jbtnClearFormat);
+               jToolBar.add(new JToolBar.Separator());
+               jbtnAnchor      = new JButtonNoFocus(actionInsertAnchor); jbtnAnchor.setIcon(getEkitIcon("Anchor")); jbtnAnchor.setText(null); jbtnAnchor.setToolTipText(Translatrix.getTranslationString("ToolAnchor")); jToolBar.add(jbtnAnchor); htTools.put(KEY_TOOL_ANCHOR, jbtnAnchor);
+               jToolBar.add(new JToolBar.Separator());
+               jtbtnViewSource = new JToggleButtonNoFocus(getEkitIcon("Source")); jtbtnViewSource.setText(null); jtbtnViewSource.setToolTipText(Translatrix.getTranslationString("ViewSource")); jtbtnViewSource.setActionCommand("viewsource"); jtbtnViewSource.addActionListener(this); jtbtnViewSource.setPreferredSize(jbtnAnchor.getPreferredSize()); jtbtnViewSource.setMinimumSize(jbtnAnchor.getMinimumSize()); jtbtnViewSource.setMaximumSize(jbtnAnchor.getMaximumSize()); jToolBar.add(jtbtnViewSource); htTools.put(KEY_TOOL_SOURCE, jtbtnViewSource);
+               jToolBar.add(new JToolBar.Separator());
+               jcmbStyleSelector = new JComboBoxNoFocus(); jToolBar.add(jcmbStyleSelector); jcmbStyleSelector.setAction(new StylesAction(jcmbStyleSelector)); htTools.put(KEY_TOOL_STYLES, jcmbStyleSelector);
+
+               /* Create the scroll area for the text pane */
+               JScrollPane jspViewport = new JScrollPane(jtpMain);
+               jspViewport.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
+               jspViewport.setPreferredSize(new Dimension(400, 400));
+               jspViewport.setMinimumSize(new Dimension(32, 32));
+
+               /* Create the scroll area for the source viewer */
+               jspSource = new JScrollPane(jtpSource);
+               jspSource.setPreferredSize(new Dimension(400, 100));
+               jspSource.setMinimumSize(new Dimension(32, 32));
+
+               jspltDisplay = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
+               jspltDisplay.setTopComponent(jspViewport);
+               if(showViewSource)
+               {
+                       jspltDisplay.setBottomComponent(jspSource);
+               }
+               else
+               {
+                       jspltDisplay.setBottomComponent(null);
+               }
+
+               iSplitPos = jspltDisplay.getDividerLocation();
+
+               registerDocumentStyles();
+
+               /* Add the components to the app */
+               this.setLayout(new BorderLayout());
+               this.add(jspltDisplay, BorderLayout.CENTER);
+       }
+
+       /** Common Constructor
+         * @param sDocument         [String]  A text or HTML document to load in the editor upon startup.
+         * @param sStyleSheet       [String]  A CSS stylesheet to load in the editor upon startup.
+         * @param showViewSource    [boolean] Specifies whether or not to show the View Source window on startup.
+         * @param showMenuIcons     [boolean] Specifies whether or not to show icon pictures in menus.
+         * @param editModeExclusive [boolean] Specifies whether or not to use exclusive edit mode (recommended on).
+         * @param sLanguage         [String]  The language portion of the Internationalization Locale to run Ekit in.
+         * @param sCountry          [String]  The country portion of the Internationalization Locale to run Ekit in.
+         */
+       public EkitCore(String sDocument, String sStyleSheet, boolean showViewSource, boolean showMenuIcons, boolean editModeExclusive, String sLanguage, String sCountry, boolean base64)
+       {
+               this(sDocument, sStyleSheet, null, null, showViewSource, showMenuIcons, editModeExclusive, sLanguage, sCountry, base64, false);
+       }
+
+       /** Default Language Constructor
+         * @param sDocument         [String]  A text or HTML document to load in the editor upon startup.
+         * @param sStyleSheet       [String]  A CSS stylesheet to load in the editor upon startup.
+         * @param showViewSource    [boolean] Specifies whether or not to show the View Source window on startup.
+         * @param showMenuIcons     [boolean] Specifies whether or not to show icon pictures in menus.
+         * @param editModeExclusive [boolean] Specifies whether or not to use exclusive edit mode (recommended on).
+         */
+       public EkitCore(String sDocument, String sStyleSheet, boolean showViewSource, boolean showMenuIcons, boolean editModeExclusive, boolean base64)
+       {
+               this(sDocument, sStyleSheet, null, null, showViewSource, showMenuIcons, editModeExclusive, null, null, base64, false);
+       }
+
+       /** Raw/Base64 Document & Style Sheet URL Constructor (Ideal for EkitApplet)
+         * @param sRawDocument      [String]  A document encoded as a String to load in the editor upon startup.
+         * @param sRawDocument      [String]  A document encoded as a String to load in the editor upon startup.
+         * @param showViewSource    [boolean] Specifies whether or not to show the View Source window on startup.
+         * @param showMenuIcons     [boolean] Specifies whether or not to show icon pictures in menus.
+         * @param editModeExclusive [boolean] Specifies whether or not to use exclusive edit mode (recommended on).
+         * @param sLanguage         [String]  The language portion of the Internationalization Locale to run Ekit in.
+         * @param sCountry          [String]  The country portion of the Internationalization Locale to run Ekit in.
+         */
+       public EkitCore(String sRawDocument, URL urlStyleSheet, boolean showViewSource, boolean showMenuIcons, boolean editModeExclusive, String sLanguage, String sCountry, boolean base64)
+       {
+               this(null, null, sRawDocument, urlStyleSheet, showViewSource, showMenuIcons, editModeExclusive, sLanguage, sCountry, base64, false);
+       }
+
+       /** Document Constructor
+         * @param sRawDocument      [String]  A document encoded as a String to load in the editor upon startup.
+         * @param showViewSource    [boolean] Specifies whether or not to show the View Source window on startup.
+         * @param showMenuIcons     [boolean] Specifies whether or not to show icon pictures in menus.
+         * @param editModeExclusive [boolean] Specifies whether or not to use exclusive edit mode (recommended on).
+         * @param sLanguage         [String]  The language portion of the Internationalization Locale to run Ekit in.
+         * @param sCountry          [String]  The country portion of the Internationalization Locale to run Ekit in.
+         */
+       public EkitCore(String sRawDocument, boolean showViewSource, boolean showMenuIcons, boolean editModeExclusive, String sLanguage, String sCountry, boolean base64)
+       {
+               this(null, null, sRawDocument, null, showViewSource, showMenuIcons, editModeExclusive, sLanguage, sCountry, base64, false);
+       }
+
+       /** Default Language & Document Constructor
+         * @param sRawDocument      [String]  A document encoded as a String to load in the editor upon startup.
+         * @param showViewSource    [boolean] Specifies whether or not to show the View Source window on startup.
+         * @param showMenuIcons     [boolean] Specifies whether or not to show icon pictures in menus.
+         * @param editModeExclusive [boolean] Specifies whether or not to use exclusive edit mode (recommended on).
+         */
+       public EkitCore(String sRawDocument, boolean showViewSource, boolean showMenuIcons, boolean editModeExclusive, boolean base64)
+       {
+               this(null, null, sRawDocument, null, showViewSource, showMenuIcons, editModeExclusive, null, null, base64, false);
+       }
+
+       /** Flags & Language Constructor
+         * @param showViewSource    [boolean] Specifies whether or not to show the View Source window on startup.
+         * @param showMenuIcons     [boolean] Specifies whether or not to show icon pictures in menus.
+         * @param editModeExclusive [boolean] Specifies whether or not to use exclusive edit mode (recommended on).
+         * @param sLanguage         [String]  The language portion of the Internationalization Locale to run Ekit in.
+         * @param sCountry          [String]  The country portion of the Internationalization Locale to run Ekit in.
+         */
+       public EkitCore(boolean showViewSource, boolean showMenuIcons, boolean editModeExclusive, String sLanguage, String sCountry)
+       {
+               this(null, null, null, null, showViewSource, showMenuIcons, editModeExclusive, sLanguage, sCountry, false, false);
+       }
+
+       /** Flags Constructor
+         * @param showViewSource    [boolean] Specifies whether or not to show the View Source window on startup.
+         * @param showMenuIcons     [boolean] Specifies whether or not to show icon pictures in menus.
+         * @param editModeExclusive [boolean] Specifies whether or not to use exclusive edit mode (recommended on).
+         */
+       public EkitCore(boolean showViewSource, boolean showMenuIcons, boolean editModeExclusive)
+       {
+               this(null, null, null, null, showViewSource, showMenuIcons, editModeExclusive, null, null, false, false);
+       }
+
+       /** Language & Debug Constructor
+         * @param sLanguage [String]  The language portion of the Internationalization Locale to run Ekit in.
+         * @param sCountry  [String]  The country portion of the Internationalization Locale to run Ekit in.
+         * @param debugMode [boolean] Specifies whether to show the Debug menu or not.
+         */
+       public EkitCore(String sLanguage, String sCountry, boolean debugMode)
+       {
+               this(null, null, null, null, false, true, true, sLanguage, sCountry, false, debugMode);
+       }
+
+       /** Language Constructor
+         * @param sLanguage [String]  The language portion of the Internationalization Locale to run Ekit in.
+         * @param sCountry  [String]  The country portion of the Internationalization Locale to run Ekit in.
+         */
+       public EkitCore(String sLanguage, String sCountry)
+       {
+               this(null, null, null, null, false, true, true, sLanguage, sCountry, false, false);
+       }
+
+       /** Debug Constructor
+         * @param debugMode [boolean] Specifies whether to show the Debug menu or not.
+         */
+       public EkitCore(boolean debugMode)
+       {
+               this(null, null, null, null, false, true, true, null, null, false, debugMode);
+       }
+
+       /** Empty Constructor
+         */
+       public EkitCore()
+       {
+               this(null, null, null, null, false, true, true, null, null, false, false);
+       }
+
+       /* ActionListener method */
+       public void actionPerformed(ActionEvent ae)
+       {
+               try
+               {
+                       String command = ae.getActionCommand();
+                       if(command.equals("newdoc"))
+                       {
+                               SimpleInfoDialog sidAsk = new SimpleInfoDialog(this.getFrame(), "", true, Translatrix.getTranslationString("AskNewDocument"), SimpleInfoDialog.QUESTION);
+                               String decision = sidAsk.getDecisionValue();
+                               if(decision.equals(Translatrix.getTranslationString("DialogAccept")))
+                               {
+                                       if(styleSheet != null)
+                                       {
+                                               htmlDoc = new ExtendedHTMLDocument(styleSheet);
+                                       }
+                                       else
+                                       {
+                                               htmlDoc = (ExtendedHTMLDocument)(htmlKit.createDefaultDocument());
+                                       }
+                                       jtpMain.setText("<HTML><BODY></BODY></HTML>");
+                                       jtpSource.setText(jtpMain.getText());
+                                       registerDocument(htmlDoc);
+                                       currentFile = null;
+                                       updateTitle();
+                               }
+                       }
+                       else if(command.equals("openhtml"))
+                       {
+                               openDocument(null);
+                       }
+                       else if(command.equals("opencss"))
+                       {
+                               openStyleSheet(null);
+                       }
+                       else if(command.equals("openb64"))
+                       {
+                               openDocumentBase64(null);
+                       }
+                       else if(command.equals("save"))
+                       {
+                               writeOut((HTMLDocument)(jtpMain.getDocument()), currentFile);
+                               updateTitle();
+                       }
+                       else if(command.equals("saveas"))
+                       {
+                               writeOut((HTMLDocument)(jtpMain.getDocument()), null);
+                       }
+                       else if(command.equals("savebody"))
+                       {
+                               writeOutFragment((HTMLDocument)(jtpMain.getDocument()),"body");
+                       }
+                       else if(command.equals("savertf"))
+                       {
+                               writeOutRTF((StyledDocument)(jtpMain.getStyledDocument()));
+                       }
+                       else if(command.equals("saveb64"))
+                       {
+                               writeOutBase64(jtpSource.getText());
+                       }
+                       else if(command.equals("textcut"))
+                       {
+                               if(jspSource.isShowing() && jtpSource.hasFocus())
+                               {
+                                       jtpSource.cut();
+                               }
+                               else
+                               {
+                                       jtpMain.cut();
+                               }
+                       }
+                       else if(command.equals("textcopy"))
+                       {
+                               if(jspSource.isShowing() && jtpSource.hasFocus())
+                               {
+                                       jtpSource.copy();
+                               }
+                               else
+                               {
+                                       jtpMain.copy();
+                               }
+                       }
+                       else if(command.equals("textpaste"))
+                       {
+                               if(jspSource.isShowing() && jtpSource.hasFocus())
+                               {
+                                       jtpSource.paste();
+                               }
+                               else
+                               {
+                                       jtpMain.paste();
+                               }
+                       }
+                       else if(command.equals("describe"))
+                       {
+                               System.out.println("------------DOCUMENT------------");
+                               System.out.println("Content Type : " + jtpMain.getContentType());
+                               System.out.println("Editor Kit   : " + jtpMain.getEditorKit());
+                               System.out.println("Doc Tree     :");
+                               System.out.println("");
+                               describeDocument(jtpMain.getStyledDocument());
+                               System.out.println("--------------------------------");
+                               System.out.println("");
+                       }
+                       else if(command.equals("describecss"))
+                       {
+                               System.out.println("-----------STYLESHEET-----------");
+                               System.out.println("Stylesheet Rules");
+                               Enumeration rules = styleSheet.getStyleNames();
+                               while(rules.hasMoreElements())
+                               {
+                                       String ruleName = (String)(rules.nextElement());
+                                       Style styleRule = styleSheet.getStyle(ruleName);
+                                       System.out.println(styleRule.toString());
+                               }
+                               System.out.println("--------------------------------");
+                               System.out.println("");
+                       }
+                       else if(command.equals("whattags"))
+                       {
+                               System.out.println("Caret Position : " + jtpMain.getCaretPosition());
+                               AttributeSet attribSet = jtpMain.getCharacterAttributes();
+                               Enumeration attribs = attribSet.getAttributeNames();
+                               System.out.println("Attributes     : ");
+                               while(attribs.hasMoreElements())
+                               {
+                                       String attribName = attribs.nextElement().toString();
+                                       System.out.println("                 " + attribName + " | " + attribSet.getAttribute(attribName));
+                               }
+                       }
+                       else if(command.equals("toggletoolbar"))
+                       {
+                               jToolBar.setVisible(jcbmiViewToolbar.isSelected());
+                       }
+                       else if(command.equals("viewsource"))
+                       {
+                               toggleSourceWindow();
+                       }
+                       else if(command.equals("serialize"))
+                       {
+                               serializeOut((HTMLDocument)(jtpMain.getDocument()));
+                       }
+                       else if(command.equals("readfromser"))
+                       {
+                               serializeIn();
+                       }
+                       else if(command.equals("inserttable"))
+                       {
+                               String[] fieldNames = { "rows", "cols", "border", "cellspacing", "cellpadding", "width" };
+                               String[] fieldTypes = { "text", "text", "text",   "text",        "text",        "text" };
+                               insertTable((Hashtable)null, fieldNames, fieldTypes);
+                       }
+                       else if(command.equals("inserttablerow"))
+                       {
+                               insertTableRow();
+                       }
+                       else if(command.equals("inserttablecolumn"))
+                       {
+                               insertTableColumn();
+                       }
+                       else if(command.equals("deletetablerow"))
+                       {
+                               deleteTableRow();
+                       }
+                       else if(command.equals("deletetablecolumn"))
+                       {
+                               deleteTableColumn();
+                       }
+                       else if(command.equals("insertbreak"))
+                       {
+                               insertBreak();
+                       }
+                       else if(command.equals("insertlocalimage"))
+                       {
+                               insertLocalImage(null);
+                       }
+                       else if(command.equals("insertserverimage"))
+                       {
+                               insertServerImage();
+                       }
+                       else if(command.equals("insertnbsp"))
+                       {
+                               insertNonbreakingSpace();
+                       }
+                       else if(command.equals("insertform"))
+                       {
+                               String[] fieldNames  = { "name", "method",   "enctype" };
+                               String[] fieldTypes  = { "text", "combo",    "text" };
+                               String[] fieldValues = { "",     "POST,GET", "text" };
+                               insertFormElement(HTML.Tag.FORM, "form", (Hashtable)null, fieldNames, fieldTypes, fieldValues, true);
+                       }
+                       else if(command.equals("inserttextfield"))
+                       {
+                               Hashtable htAttribs = new Hashtable();
+                               htAttribs.put("type", "text");
+                               String[] fieldNames = { "name", "value", "size", "maxlength" };
+                               String[] fieldTypes = { "text", "text",  "text", "text" };
+                               insertFormElement(HTML.Tag.INPUT, "input", htAttribs, fieldNames, fieldTypes, false);
+                       }
+                       else if(command.equals("inserttextarea"))
+                       {
+                               String[] fieldNames = { "name", "rows", "cols" };
+                               String[] fieldTypes = { "text", "text", "text" };
+                               insertFormElement(HTML.Tag.TEXTAREA, "textarea", (Hashtable)null, fieldNames, fieldTypes, true);
+                       }
+                       else if(command.equals("insertcheckbox"))
+                       {
+                               Hashtable htAttribs = new Hashtable();
+                               htAttribs.put("type", "checkbox");
+                               String[] fieldNames = { "name", "checked" };
+                               String[] fieldTypes = { "text", "bool" };
+                               insertFormElement(HTML.Tag.INPUT, "input", htAttribs, fieldNames, fieldTypes, false);
+                       }
+                       else if(command.equals("insertradiobutton"))
+                       {
+                               Hashtable htAttribs = new Hashtable();
+                               htAttribs.put("type", "radio");
+                               String[] fieldNames = { "name", "checked" };
+                               String[] fieldTypes = { "text", "bool" };
+                               insertFormElement(HTML.Tag.INPUT, "input", htAttribs, fieldNames, fieldTypes, false);
+                       }
+                       else if(command.equals("insertpassword"))
+                       {
+                               Hashtable htAttribs = new Hashtable();
+                               htAttribs.put("type", "password");
+                               String[] fieldNames = { "name", "value", "size", "maxlength" };
+                               String[] fieldTypes = { "text", "text",  "text", "text" };
+                               insertFormElement(HTML.Tag.INPUT, "input", htAttribs, fieldNames, fieldTypes, false);
+                       }
+                       else if(command.equals("insertbutton"))
+                       {
+                               Hashtable htAttribs = new Hashtable();
+                               htAttribs.put("type", "button");
+                               String[] fieldNames = { "name", "value" };
+                               String[] fieldTypes = { "text", "text" };
+                               insertFormElement(HTML.Tag.INPUT, "input", htAttribs, fieldNames, fieldTypes, false);
+                       }
+                       else if(command.equals("insertbuttonsubmit"))
+                       {
+                               Hashtable htAttribs = new Hashtable();
+                               htAttribs.put("type", "submit");
+                               String[] fieldNames = { "name", "value" };
+                               String[] fieldTypes = { "text", "text" };
+                               insertFormElement(HTML.Tag.INPUT, "input", htAttribs, fieldNames, fieldTypes, false);
+                       }
+                       else if(command.equals("insertbuttonreset"))
+                       {
+                               Hashtable htAttribs = new Hashtable();
+                               htAttribs.put("type", "reset");
+                               String[] fieldNames = { "name", "value" };
+                               String[] fieldTypes = { "text", "text" };
+                               insertFormElement(HTML.Tag.INPUT, "input", htAttribs, fieldNames, fieldTypes, false);
+                       }
+                       else if(command.equals("find"))
+                       {
+                               doSearch((String)null, (String)null, false, lastSearchCaseSetting, lastSearchTopSetting);
+                       }
+                       else if(command.equals("findagain"))
+                       {
+                               doSearch(lastSearchFindTerm, (String)null, false, lastSearchCaseSetting, false);
+                       }
+                       else if(command.equals("replace"))
+                       {
+                               doSearch((String)null, (String)null, true, lastSearchCaseSetting, lastSearchTopSetting);
+                       }
+                       else if(command.equals("exit"))
+                       {
+                               this.dispose();
+                       }
+                       else if(command.equals("helpabout"))
+                       {
+                               SimpleInfoDialog sidAbout = new SimpleInfoDialog(this.getFrame(), Translatrix.getTranslationString("About"), true, Translatrix.getTranslationString("AboutMessage"), SimpleInfoDialog.INFO);
+                       }
+               }
+               catch(IOException ioe)
+               {
+                       logException("IOException in actionPerformed method", ioe);
+                       SimpleInfoDialog sidAbout = new SimpleInfoDialog(this.getFrame(), Translatrix.getTranslationString("Error"), true, Translatrix.getTranslationString("ErrorIOException"), SimpleInfoDialog.ERROR);
+               }
+               catch(BadLocationException ble)
+               {
+                       logException("BadLocationException in actionPerformed method", ble);
+                       SimpleInfoDialog sidAbout = new SimpleInfoDialog(this.getFrame(), Translatrix.getTranslationString("Error"), true, Translatrix.getTranslationString("ErrorBadLocationException"), SimpleInfoDialog.ERROR);
+               }
+               catch(NumberFormatException nfe)
+               {
+                       logException("NumberFormatException in actionPerformed method", nfe);
+                       SimpleInfoDialog sidAbout = new SimpleInfoDialog(this.getFrame(), Translatrix.getTranslationString("Error"), true, Translatrix.getTranslationString("ErrorNumberFormatException"), SimpleInfoDialog.ERROR);
+               }
+               catch(ClassNotFoundException cnfe)
+               {
+                       logException("ClassNotFound Exception in actionPerformed method", cnfe);
+                       SimpleInfoDialog sidAbout = new SimpleInfoDialog(this.getFrame(), Translatrix.getTranslationString("Error"), true, Translatrix.getTranslationString("ErrorClassNotFoundException "), SimpleInfoDialog.ERROR);
+               }
+               catch(RuntimeException re)
+               {
+                       logException("RuntimeException in actionPerformed method", re);
+                       SimpleInfoDialog sidAbout = new SimpleInfoDialog(this.getFrame(), Translatrix.getTranslationString("Error"), true, Translatrix.getTranslationString("ErrorRuntimeException"), SimpleInfoDialog.ERROR);
+               }
+       }
+
+       /* KeyListener methods */
+       public void keyTyped(KeyEvent ke)
+       {
+               Element elem;
+               String selectedText;
+               int pos = this.getCaretPosition();
+               int repos = -1;
+               if(ke.getKeyChar() == KeyEvent.VK_BACK_SPACE)
+               {
+                       try
+                       {
+                               if(pos > 0)
+                               {
+                                       if((selectedText = jtpMain.getSelectedText()) != null)
+                                       {
+                                               htmlUtilities.delete();
+                                               return;
+                                       }
+                                       else
+                                       {
+                                               int sOffset = htmlDoc.getParagraphElement(pos).getStartOffset();
+                                               if(sOffset == jtpMain.getSelectionStart())
+                                               {
+                                                       boolean content = true;
+                                                       if(htmlUtilities.checkParentsTag(HTML.Tag.LI))
+                                                       {
+                                                               elem = htmlUtilities.getListItemParent();
+                                                               content = false;
+                                                               int so = elem.getStartOffset();
+                                                               int eo = elem.getEndOffset();
+                                                               if(so + 1 < eo)
+                                                               {
+                                                                       char[] temp = jtpMain.getText(so, eo - so).toCharArray();
+                                                                       for(int i=0; i < temp.length; i++)
+                                                                       {
+                                                                               if(!(new Character(temp[i])).isWhitespace(temp[i]))
+                                                                               {
+                                                                                       content = true;
+                                                                               }
+                                                                       }
+                                                               }
+                                                               if(!content)
+                                                               {
+                                                                       Element listElement = elem.getParentElement();
+                                                                       htmlUtilities.removeTag(elem, true);
+                                                                       this.setCaretPosition(sOffset - 1);
+                                                                       return;
+                                                               }
+                                                               else
+                                                               {
+                                                                       jtpMain.setCaretPosition(jtpMain.getCaretPosition() - 1);
+                                                                       jtpMain.moveCaretPosition(jtpMain.getCaretPosition() - 2);
+                                                                       jtpMain.replaceSelection("");
+                                                                       return;
+                                                               }
+                                                       }
+                                                       else if(htmlUtilities.checkParentsTag(HTML.Tag.TABLE))
+                                                       {
+                                                               jtpMain.setCaretPosition(jtpMain.getCaretPosition() - 1);
+                                                               ke.consume();
+                                                               return;
+                                                       }
+                                               }
+                                               jtpMain.replaceSelection("");
+                                               return;
+                                       }
+                               }
+                       }
+                       catch (BadLocationException ble)
+                       {
+                               logException("BadLocationException in keyTyped method", ble);
+                               SimpleInfoDialog sidAbout = new SimpleInfoDialog(this.getFrame(), Translatrix.getTranslationString("Error"), true, Translatrix.getTranslationString("ErrorBadLocationException"), SimpleInfoDialog.ERROR);
+                       }
+                       catch (IOException ioe)
+                       {
+                               logException("IOException in keyTyped method", ioe);
+                               SimpleInfoDialog sidAbout = new SimpleInfoDialog(this.getFrame(), Translatrix.getTranslationString("Error"), true, Translatrix.getTranslationString("ErrorIOException"), SimpleInfoDialog.ERROR);
+                       }
+               }
+               else if(ke.getKeyChar() == KeyEvent.VK_ENTER)
+               {
+                       try
+                       {
+                               if(htmlUtilities.checkParentsTag(HTML.Tag.UL) == true | htmlUtilities.checkParentsTag(HTML.Tag.OL) == true)
+                               {
+                                       elem = htmlUtilities.getListItemParent();
+                                       int so = elem.getStartOffset();
+                                       int eo = elem.getEndOffset();
+                                       char[] temp = this.getTextPane().getText(so,eo-so).toCharArray();
+                                       boolean content = false;
+                                       for(int i=0;i<temp.length;i++)
+                                       {
+                                               if(!(new Character(temp[i])).isWhitespace(temp[i]))
+                                               {
+                                                       content = true;
+                                               }
+                                       }
+                                       if(content)
+                                       {
+                                               int end = -1;
+                                               int j = temp.length;
+                                               do
+                                               {
+                                                       j--;
+                                                       if(new Character(temp[j]).isLetterOrDigit(temp[j]))
+                                                       {
+                                                               end = j;
+                                                       }
+                                               } while (end == -1 && j >= 0);
+                                               j = end;
+                                               do
+                                               {
+                                                       j++;
+                                                       if(!new Character(temp[j]).isSpaceChar(temp[j]))
+                                                       {
+                                                               repos = j - end -1;
+                                                       }
+                                               } while (repos == -1 && j < temp.length);
+                                               if(repos == -1)
+                                               {
+                                                       repos = 0;
+                                               }
+                                       }
+                                       if(elem.getStartOffset() == elem.getEndOffset() || !content)
+                                       {
+                                               manageListElement(elem);
+                                       }
+                                       else
+                                       {
+                                               if(this.getCaretPosition() + 1 == elem.getEndOffset())
+                                               {
+                                                       insertListStyle(elem);
+                                                       this.setCaretPosition(pos - repos);
+                                               }
+                                               else
+                                               {
+                                                       int caret = this.getCaretPosition();
+                                                       String tempString = this.getTextPane().getText(caret, eo - caret);
+                                                       this.getTextPane().select(caret, eo - 1);
+                                                       this.getTextPane().replaceSelection("");
+                                                       htmlUtilities.insertListElement(tempString);
+                                                       Element newLi = htmlUtilities.getListItemParent();
+                                                       this.setCaretPosition(newLi.getEndOffset() - 1);
+                                               }
+                                       }
+                               }
+                       }
+                       catch (BadLocationException ble)
+                       {
+                               logException("BadLocationException in keyTyped method", ble);
+                               SimpleInfoDialog sidAbout = new SimpleInfoDialog(this.getFrame(), Translatrix.getTranslationString("Error"), true, Translatrix.getTranslationString("ErrorBadLocationException"), SimpleInfoDialog.ERROR);
+                       }
+                       catch (IOException ioe)
+                       {
+                               logException("IOException in keyTyped method", ioe);
+                               SimpleInfoDialog sidAbout = new SimpleInfoDialog(this.getFrame(), Translatrix.getTranslationString("Error"), true, Translatrix.getTranslationString("ErrorIOException"), SimpleInfoDialog.ERROR);
+                       }
+               }
+       }
+       public void keyPressed(KeyEvent e) {}
+       public void keyReleased(KeyEvent e) {}
+
+       public void insertListStyle(Element element)
+       throws BadLocationException,IOException
+       {
+               if(element.getParentElement().getName() == "ol")
+               {
+                       actionListOrdered.actionPerformed(new ActionEvent(new Object(), 0, "newListPoint"));
+               }
+               else
+               {
+                       actionListUnordered.actionPerformed(new ActionEvent(new Object(), 0, "newListPoint"));
+               }
+       }
+
+       /* DocumentListener methods */
+       public void changedUpdate(DocumentEvent de)     { handleDocumentChange(de); }
+       public void insertUpdate(DocumentEvent de)      { handleDocumentChange(de); }
+       public void removeUpdate(DocumentEvent de)      { handleDocumentChange(de); }
+       public void handleDocumentChange(DocumentEvent de)
+       {
+               if(!exclusiveEdit)
+               {
+                       if(jspSource.isShowing())
+                       {
+                               if(de.getDocument() instanceof HTMLDocument || de.getDocument() instanceof ExtendedHTMLDocument)
+                               {
+                                       jtpSource.getDocument().removeDocumentListener(this);
+                                       jtpSource.setText(jtpMain.getText());
+                                       jtpSource.getDocument().addDocumentListener(this);
+                               }
+                               else if(de.getDocument() instanceof PlainDocument || de.getDocument() instanceof DefaultStyledDocument)
+                               {
+                                       jtpMain.getDocument().removeDocumentListener(this);
+                                       jtpMain.setText(jtpSource.getText());
+                                       jtpMain.getDocument().addDocumentListener(this);
+                               }
+                       }
+               }
+       }
+
+       /** Method for setting a document as the current document for the text pane
+         * and re-registering the controls and settings for it
+         */
+       public void registerDocument(ExtendedHTMLDocument htmlDoc)
+       {
+               jtpMain.setDocument(htmlDoc);
+               jtpMain.getDocument().addUndoableEditListener(new CustomUndoableEditListener());
+               jtpMain.getDocument().addDocumentListener(this);
+               purgeUndos();
+               registerDocumentStyles();
+       }
+
+       /** Method for locating the available CSS style for the document and adding
+         * them to the styles selector
+         */
+       public void registerDocumentStyles()
+       {
+               if(jcmbStyleSelector == null || htmlDoc == null)
+               {
+                       return;
+               }
+               jcmbStyleSelector.setEnabled(false);
+               jcmbStyleSelector.removeAllItems();
+               jcmbStyleSelector.addItem(Translatrix.getTranslationString("NoCSSStyle"));
+               for(Enumeration e = htmlDoc.getStyleNames(); e.hasMoreElements();)
+               {
+                       String name = (String) e.nextElement();
+                       if(name.length() > 0 && name.charAt(0) == '.')
+                       {
+                               jcmbStyleSelector.addItem(name.substring(1));
+                       }
+               }
+               jcmbStyleSelector.setEnabled(true);
+       }
+
+       /** Method for inserting an HTML Table
+         */
+       private void insertTable(Hashtable attribs, String[] fieldNames, String[] fieldTypes)
+       throws IOException, BadLocationException, RuntimeException, NumberFormatException
+       {
+               int caretPos = jtpMain.getCaretPosition();
+               StringBuffer compositeElement = new StringBuffer("<TABLE");
+               if(attribs != null && attribs.size() > 0)
+               {
+                       Enumeration attribEntries = attribs.keys();
+                       while(attribEntries.hasMoreElements())
+                       {
+                               Object entryKey   = attribEntries.nextElement();
+                               Object entryValue = attribs.get(entryKey);
+                               if(entryValue != null && entryValue != "")
+                               {
+                                       compositeElement.append(" " + entryKey + "=" + '"' + entryValue + '"');
+                               }
+                       }
+               }
+               int rows = 0;
+               int cols = 0;
+               if(fieldNames != null && fieldNames.length > 0)
+               {
+                       PropertiesDialog propertiesDialog = new PropertiesDialog(this.getFrame(), fieldNames, fieldTypes, Translatrix.getTranslationString("FormDialogTitle"), true);
+                       propertiesDialog.show();
+                       String decision = propertiesDialog.getDecisionValue();
+                       if(decision.equals(Translatrix.getTranslationString("DialogCancel")))
+                       {
+                               propertiesDialog.dispose();
+                               propertiesDialog = null;
+                               return;
+                       }
+                       else
+                       {
+                               for(int iter = 0; iter < fieldNames.length; iter++)
+                               {
+                                       String fieldName = fieldNames[iter];
+                                       String propValue = propertiesDialog.getFieldValue(fieldName);
+                                       if(propValue != null && propValue != "" && propValue.length() > 0)
+                                       {
+                                               if(fieldName.equals("rows"))
+                                               {
+                                                       rows = Integer.parseInt(propValue);
+                                               }
+                                               else if(fieldName.equals("cols"))
+                                               {
+                                                       cols = Integer.parseInt(propValue);
+                                               }
+                                               else
+                                               {
+                                                       compositeElement.append(" " + fieldName + "=" + '"' + propValue + '"');
+                                               }
+                                       }
+                               }
+                       }
+                       propertiesDialog.dispose();
+                       propertiesDialog = null;
+               }
+               compositeElement.append(">");
+               for(int i = 0; i < rows; i++)
+               {
+                       compositeElement.append("<TR>");
+                       for(int j = 0; j < cols; j++)
+                       {
+                               compositeElement.append("<TD></TD>");
+                       }
+                       compositeElement.append("</TR>");
+               }
+               compositeElement.append("</TABLE><P>&nbsp;<P>");
+               htmlKit.insertHTML(htmlDoc, caretPos, compositeElement.toString(), 0, 0, HTML.Tag.TABLE);
+               jtpMain.setCaretPosition(caretPos + 1);
+               refreshOnUpdate();
+       }
+
+       /** Method for inserting a row into an HTML Table
+         */
+       private void insertTableRow()
+       {
+               int caretPos = jtpMain.getCaretPosition();
+               Element element = htmlDoc.getCharacterElement(jtpMain.getCaretPosition());
+               Element elementParent = element.getParentElement();
+               int startPoint  = -1;
+               int columnCount = -1;
+               while(elementParent != null && !elementParent.getName().equals("body"))
+               {
+                       if(elementParent.getName().equals("tr"))
+                       {
+                               startPoint  = elementParent.getStartOffset();
+                               columnCount = elementParent.getElementCount();
+                               break;
+                       }
+                       else
+                       {
+                               elementParent = elementParent.getParentElement();
+                       }
+               }
+               if(startPoint > -1 && columnCount > -1)
+               {
+                       jtpMain.setCaretPosition(startPoint);
+                       StringBuffer sRow = new StringBuffer();
+                       sRow.append("<TR>");
+                       for(int i = 0; i < columnCount; i++)
+                       {
+                               sRow.append("<TD></TD>");
+                       }
+                       sRow.append("</TR>");
+                       ActionEvent actionEvent = new ActionEvent(jtpMain, 0, "insertTableRow");
+                       new HTMLEditorKit.InsertHTMLTextAction("insertTableRow", sRow.toString(), HTML.Tag.TABLE, HTML.Tag.TR).actionPerformed(actionEvent);
+                       refreshOnUpdate();
+                       jtpMain.setCaretPosition(caretPos);
+               }
+       }
+
+       /** Method for inserting a column into an HTML Table
+         */
+       private void insertTableColumn()
+       {
+               int caretPos = jtpMain.getCaretPosition();
+               Element element = htmlDoc.getCharacterElement(jtpMain.getCaretPosition());
+               Element elementParent = element.getParentElement();
+               int startPoint = -1;
+               int rowCount   = -1;
+               int cellOffset =  0;
+               while(elementParent != null && !elementParent.getName().equals("body"))
+               {
+                       if(elementParent.getName().equals("table"))
+                       {
+                               startPoint = elementParent.getStartOffset();
+                               rowCount   = elementParent.getElementCount();
+                               break;
+                       }
+                       else if(elementParent.getName().equals("tr"))
+                       {
+                               int rowStart = elementParent.getStartOffset();
+                               int rowCells = elementParent.getElementCount();
+                               for(int i = 0; i < rowCells; i++)
+                               {
+                                       Element currentCell = elementParent.getElement(i);
+                                       if(jtpMain.getCaretPosition() >= currentCell.getStartOffset() && jtpMain.getCaretPosition() <= currentCell.getEndOffset())
+                                       {
+                                               cellOffset = i;
+                                       }
+                               }
+                               elementParent = elementParent.getParentElement();
+                       }
+                       else
+                       {
+                               elementParent = elementParent.getParentElement();
+                       }
+               }
+               if(startPoint > -1 && rowCount > -1)
+               {
+                       jtpMain.setCaretPosition(startPoint);
+                       String sCell = "<TD></TD>";
+                       ActionEvent actionEvent = new ActionEvent(jtpMain, 0, "insertTableCell");
+                       for(int i = 0; i < rowCount; i++)
+                       {
+                               Element row = elementParent.getElement(i);
+                               Element whichCell = row.getElement(cellOffset);
+                               jtpMain.setCaretPosition(whichCell.getStartOffset());
+                               new HTMLEditorKit.InsertHTMLTextAction("insertTableCell", sCell, HTML.Tag.TR, HTML.Tag.TD, HTML.Tag.TH, HTML.Tag.TD).actionPerformed(actionEvent);
+                       }
+                       refreshOnUpdate();
+                       jtpMain.setCaretPosition(caretPos);
+               }
+       }
+
+       /** Method for inserting a cell into an HTML Table
+         */
+       private void insertTableCell()
+       {
+               String sCell = "<TD></TD>";
+               ActionEvent actionEvent = new ActionEvent(jtpMain, 0, "insertTableCell");
+               new HTMLEditorKit.InsertHTMLTextAction("insertTableCell", sCell, HTML.Tag.TR, HTML.Tag.TD, HTML.Tag.TH, HTML.Tag.TD).actionPerformed(actionEvent);
+               refreshOnUpdate();
+       }
+
+       /** Method for deleting a row from an HTML Table
+         */
+       private void deleteTableRow()
+       throws BadLocationException
+       {
+               int caretPos = jtpMain.getCaretPosition();
+               Element element = htmlDoc.getCharacterElement(jtpMain.getCaretPosition());
+               Element elementParent = element.getParentElement();
+               int startPoint = -1;
+               int endPoint   = -1;
+               while(elementParent != null && !elementParent.getName().equals("body"))
+               {
+                       if(elementParent.getName().equals("tr"))
+                       {
+                               startPoint = elementParent.getStartOffset();
+                               endPoint   = elementParent.getEndOffset();
+                               break;
+                       }
+                       else
+                       {
+                               elementParent = elementParent.getParentElement();
+                       }
+               }
+               if(startPoint > -1 && endPoint > startPoint)
+               {
+                       htmlDoc.remove(startPoint, endPoint - startPoint);
+                       jtpMain.setDocument(htmlDoc);
+                       registerDocument(htmlDoc);
+                       refreshOnUpdate();
+                       if(caretPos >= htmlDoc.getLength())
+                       {
+                               caretPos = htmlDoc.getLength() - 1;
+                       }
+                       jtpMain.setCaretPosition(caretPos);
+               }
+       }
+
+       /** Method for deleting a column from an HTML Table
+         */
+       private void deleteTableColumn()
+       throws BadLocationException
+       {
+               int caretPos = jtpMain.getCaretPosition();
+               Element element       = htmlDoc.getCharacterElement(jtpMain.getCaretPosition());
+               Element elementParent = element.getParentElement();
+               Element elementCell   = (Element)null;
+               Element elementRow    = (Element)null;
+               Element elementTable  = (Element)null;
+               // Locate the table, row, and cell location of the cursor
+               while(elementParent != null && !elementParent.getName().equals("body"))
+               {
+                       if(elementParent.getName().equals("td"))
+                       {
+                               elementCell = elementParent;
+                       }
+                       else if(elementParent.getName().equals("tr"))
+                       {
+                               elementRow = elementParent;
+                       }
+                       else if(elementParent.getName().equals("table"))
+                       {
+                               elementTable = elementParent;
+                       }
+                       elementParent = elementParent.getParentElement();
+               }
+               int whichColumn = -1;
+               if(elementCell != null && elementRow != null && elementTable != null)
+               {
+                       // Find the column the cursor is in
+                       for(int i = 0; i < elementRow.getElementCount(); i++)
+                       {
+                               if(elementCell == elementRow.getElement(i))
+                               {
+                                       whichColumn = i;
+                               }
+                       }
+                       if(whichColumn > -1)
+                       {
+                               // Iterate through the table rows, deleting cells from the indicated column
+                               for(int i = 0; i < elementTable.getElementCount(); i++)
+                               {
+                                       elementRow  = elementTable.getElement(i);
+                                       elementCell = (elementRow.getElementCount() > whichColumn ? elementRow.getElement(whichColumn) : elementRow.getElement(elementRow.getElementCount() - 1));
+                                       int columnCellStart = elementCell.getStartOffset();
+                                       int columnCellEnd   = elementCell.getEndOffset();
+                                       htmlDoc.remove(columnCellStart, columnCellEnd - columnCellStart);
+                               }
+                               jtpMain.setDocument(htmlDoc);
+                               registerDocument(htmlDoc);
+                               refreshOnUpdate();
+                               if(caretPos >= htmlDoc.getLength())
+                               {
+                                       caretPos = htmlDoc.getLength() - 1;
+                               }
+                               jtpMain.setCaretPosition(caretPos);
+                       }
+               }
+       }
+
+       /** Method for inserting a break (BR) element
+         */
+       private void insertBreak()
+       throws IOException, BadLocationException, RuntimeException
+       {
+               int caretPos = jtpMain.getCaretPosition();
+               htmlKit.insertHTML(htmlDoc, caretPos, "<BR>", 0, 0, HTML.Tag.BR);
+               jtpMain.setCaretPosition(caretPos + 1);
+       }
+
+       /** Method for inserting a non-breaking space (&nbsp;)
+         */
+       private void insertNonbreakingSpace()
+       throws IOException, BadLocationException, RuntimeException
+       {
+               int caretPos = jtpMain.getCaretPosition();
+               htmlDoc.insertString(caretPos, "\240", jtpMain.getInputAttributes());
+               jtpMain.setCaretPosition(caretPos + 1);
+       }
+
+       /** Method for inserting a form element
+         */
+       private void insertFormElement(HTML.Tag baseTag, String baseElement, Hashtable attribs, String[] fieldNames, String[] fieldTypes, String[] fieldValues, boolean hasClosingTag)
+       throws IOException, BadLocationException, RuntimeException
+       {
+               int caretPos = jtpMain.getCaretPosition();
+               StringBuffer compositeElement = new StringBuffer("<" + baseElement);
+               if(attribs != null && attribs.size() > 0)
+               {
+                       Enumeration attribEntries = attribs.keys();
+                       while(attribEntries.hasMoreElements())
+                       {
+                               Object entryKey   = attribEntries.nextElement();
+                               Object entryValue = attribs.get(entryKey);
+                               if(entryValue != null && entryValue != "")
+                               {
+                                       compositeElement.append(" " + entryKey + "=" + '"' + entryValue + '"');
+                               }
+                       }
+               }
+               if(fieldNames != null && fieldNames.length > 0)
+               {
+                       PropertiesDialog propertiesDialog = new PropertiesDialog(this.getFrame(), fieldNames, fieldTypes, fieldValues, Translatrix.getTranslationString("FormDialogTitle"), true);
+                       propertiesDialog.show();
+                       String decision = propertiesDialog.getDecisionValue();
+                       if(decision.equals(Translatrix.getTranslationString("DialogCancel")))
+                       {
+                               propertiesDialog.dispose();
+                               propertiesDialog = null;
+                               return;
+                       }
+                       else
+                       {
+                               for(int iter = 0; iter < fieldNames.length; iter++)
+                               {
+                                       String fieldName = fieldNames[iter];
+                                       String propValue = propertiesDialog.getFieldValue(fieldName);
+                                       if(propValue != null && propValue.length() > 0)
+                                       {
+                                               if(fieldName.equals("checked"))
+                                               {
+                                                       if(propValue.equals("true"))
+                                                       {
+                                                               compositeElement.append(" " + fieldName + "=" + '"' + propValue + '"');
+                                                       }
+                                               }
+                                               else
+                                               {
+                                                       compositeElement.append(" " + fieldName + "=" + '"' + propValue + '"');
+                                               }
+                                       }
+                               }
+                       }
+                       propertiesDialog.dispose();
+                       propertiesDialog = null;
+               }
+               // --- Convenience for editing, this makes the FORM visible
+               if(useFormIndicator && baseElement.equals("form"))
+               {
+                       compositeElement.append(" bgcolor=" + '"' + clrFormIndicator + '"');
+               }
+               // --- END
+               compositeElement.append(">");
+               if(hasClosingTag)
+               {
+                       compositeElement.append("</" + baseElement + ">");
+               }
+               if(baseTag == HTML.Tag.FORM)
+               {
+                       compositeElement.append("<P>&nbsp;</P>");
+               }
+               htmlKit.insertHTML(htmlDoc, caretPos, compositeElement.toString(), 0, 0, baseTag);
+               // jtpMain.setCaretPosition(caretPos + 1);
+               refreshOnUpdate();
+       }
+
+       /** Alternate method call for inserting a form element
+         */
+       private void insertFormElement(HTML.Tag baseTag, String baseElement, Hashtable attribs, String[] fieldNames, String[] fieldTypes, boolean hasClosingTag)
+       throws IOException, BadLocationException, RuntimeException
+       {
+               insertFormElement(baseTag, baseElement, attribs, fieldNames, fieldTypes, new String[fieldNames.length], hasClosingTag);
+       }
+
+       /** Method that handles initial list insertion and deletion
+         */
+       public void manageListElement(Element element)
+       {
+               Element h = htmlUtilities.getListItemParent();
+               Element listElement = h.getParentElement();
+               if(h != null)
+               {
+                       htmlUtilities.removeTag(h, true);
+               }
+       }
+
+       /** Method to initiate a find/replace operation
+         */
+       private void doSearch(String searchFindTerm, String searchReplaceTerm, boolean bIsFindReplace, boolean bCaseSensitive, boolean bStartAtTop)
+       {
+               boolean bReplaceAll = false;
+               JTextPane searchPane = jtpMain;
+               if(jspSource.isShowing() || jtpSource.hasFocus())
+               {
+                       searchPane = jtpSource;
+               }
+               if(searchFindTerm == null || (bIsFindReplace && searchReplaceTerm == null))
+               {
+                       SearchDialog sdSearchInput = new SearchDialog(this.getFrame(), Translatrix.getTranslationString("SearchDialogTitle"), true, bIsFindReplace, bCaseSensitive, bStartAtTop);
+                       searchFindTerm    = sdSearchInput.getFindTerm();
+                       searchReplaceTerm = sdSearchInput.getReplaceTerm();
+                       bCaseSensitive    = sdSearchInput.getCaseSensitive();
+                       bStartAtTop       = sdSearchInput.getStartAtTop();
+                       bReplaceAll       = sdSearchInput.getReplaceAll();
+               }
+               if(searchFindTerm != null && (!bIsFindReplace || searchReplaceTerm != null))
+               {
+                       if(bReplaceAll)
+                       {
+                               int results = findText(searchFindTerm, searchReplaceTerm, bCaseSensitive, 0);
+                               int findOffset = 0;
+                               if(results > -1)
+                               {
+                                       while(results > -1)
+                                       {
+                                               findOffset = findOffset + searchReplaceTerm.length();
+                                               results    = findText(searchFindTerm, searchReplaceTerm, bCaseSensitive, findOffset);
+                                       }
+                               }
+                               else
+                               {
+                                       SimpleInfoDialog sidWarn = new SimpleInfoDialog(this.getFrame(), "", true, Translatrix.getTranslationString("ErrorNoOccurencesFound") + ":\n" + searchFindTerm, SimpleInfoDialog.WARNING);
+                               }
+                       }
+                       else
+                       {
+                               int results = findText(searchFindTerm, searchReplaceTerm, bCaseSensitive, (bStartAtTop ? 0 : searchPane.getCaretPosition()));
+                               if(results == -1)
+                               {
+                                       SimpleInfoDialog sidWarn = new SimpleInfoDialog(this.getFrame(), "", true, Translatrix.getTranslationString("ErrorNoMatchFound") + ":\n" + searchFindTerm, SimpleInfoDialog.WARNING);
+                               }
+                       }
+                       lastSearchFindTerm    = new String(searchFindTerm);
+                       if(searchReplaceTerm != null)
+                       {
+                               lastSearchReplaceTerm = new String(searchReplaceTerm);
+                       }
+                       else
+                       {
+                               lastSearchReplaceTerm = (String)null;
+                       }
+                       lastSearchCaseSetting = bCaseSensitive;
+                       lastSearchTopSetting  = bStartAtTop;
+               }
+       }
+
+       /** Method for finding (and optionally replacing) a string in the text
+         */
+       private int findText(String findTerm, String replaceTerm, boolean bCaseSenstive, int iOffset)
+       {
+               JTextPane jtpFindSource;
+               if(jspSource.isShowing() || jtpSource.hasFocus())
+               {
+                       jtpFindSource = jtpSource;
+               }
+               else
+               {
+                       jtpFindSource = jtpMain;
+               }
+               int searchPlace = -1;
+               try
+               {
+                       Document baseDocument = jtpFindSource.getDocument();
+                       searchPlace =
+                               (bCaseSenstive ?
+                                       baseDocument.getText(0, baseDocument.getLength()).indexOf(findTerm, iOffset) :
+                                       baseDocument.getText(0, baseDocument.getLength()).toLowerCase().indexOf(findTerm.toLowerCase(), iOffset)
+                               );
+                       if(searchPlace > -1)
+                       {
+                               if(replaceTerm != null)
+                               {
+                                       AttributeSet attribs = null;
+                                       if(baseDocument instanceof HTMLDocument)
+                                       {
+                                               Element element = ((HTMLDocument)baseDocument).getCharacterElement(searchPlace);
+                                               attribs = element.getAttributes();
+                                       }
+                                       baseDocument.remove(searchPlace, findTerm.length());
+                                       baseDocument.insertString(searchPlace, replaceTerm, attribs);
+                                       jtpFindSource.setCaretPosition(searchPlace + replaceTerm.length());
+                                       jtpFindSource.requestFocus();
+                                       jtpFindSource.select(searchPlace, searchPlace + replaceTerm.length());
+                               }
+                               else
+                               {
+                                       jtpFindSource.setCaretPosition(searchPlace + findTerm.length());
+                                       jtpFindSource.requestFocus();
+                                       jtpFindSource.select(searchPlace, searchPlace + findTerm.length());
+                               }
+                       }
+               }
+               catch(BadLocationException ble)
+               {
+                       logException("BadLocationException in actionPerformed method", ble);
+                       SimpleInfoDialog sidAbout = new SimpleInfoDialog(this.getFrame(), Translatrix.getTranslationString("Error"), true, Translatrix.getTranslationString("ErrorBadLocationException"), SimpleInfoDialog.ERROR);
+               }
+               return searchPlace;
+       }
+
+       /** Method for inserting an image from a file
+         */
+       private void insertLocalImage(File whatImage)
+       throws IOException, BadLocationException, RuntimeException
+       {
+               if(whatImage == null)
+               {
+                       whatImage = getImageFromChooser(".", extsIMG, Translatrix.getTranslationString("FiletypeIMG"));
+               }
+               if(whatImage != null)
+               {
+                       int caretPos = jtpMain.getCaretPosition();
+                       htmlKit.insertHTML(htmlDoc, caretPos, "<IMG SRC=\"" + whatImage + "\">", 0, 0, HTML.Tag.IMG);
+                       jtpMain.setCaretPosition(caretPos + 1);
+                       refreshOnUpdate();
+               }
+       }
+
+       /** Method for inserting an image from a server
+         */
+       private void insertServerImage()
+       throws BadLocationException
+       {
+               if(ServletURL != null)
+               {
+                       try
+                       {
+                               URL theServlet = new URL(ServletURL + "?GetImages=" + TreePilotSystemID + "&ImageExtensions=" + TreePilotProperties.getString("ValidImageExtensions"));
+                               URLConnection conn = theServlet.openConnection();
+                               ObjectInputStream in = new ObjectInputStream(conn.getInputStream());
+                               String[] imageList = (String[]) in.readObject();
+                               int caretPos = jtpMain.getCaretPosition();
+                               ImageDialog imageDialog = new ImageDialog(this, ImageDir + TreePilotSystemID, imageList, "Image Chooser", true);
+                               String selectedImage = imageDialog.getSelectedImage();
+                               imageDialog.dispose();
+                               if(selectedImage != null  && !selectedImage.equals(""))
+                               {
+                                       htmlKit.insertHTML(htmlDoc, caretPos, selectedImage, 0, 0, HTML.Tag.IMG);
+                                       jtpMain.setCaretPosition(caretPos + 1);
+                               }
+                               jtpMain.requestFocus();
+                               in.close();
+                       }
+                       catch (MalformedURLException mue)
+                       {
+                               System.err.println("MalFormedURLException during insertImage " + mue);
+                       }
+                       catch (IOException ie)
+                       {
+                               System.err.println("IOException during insertImage " + ie);
+                       }
+                       catch (ClassNotFoundException cnfe)
+                       {
+                               System.err.println("ClassNotFoundException during insertImage" + cnfe);
+                       }
+               }
+       }
+
+       /** Method for inserting an image
+         */
+       public String insertFile()
+       {
+               String selectedFile = null;
+               if(ServletURL != null)
+               {
+                       try
+                       {
+                               URL theServlet = new URL(ServletURL + "?GetFiles=" + TreePilotSystemID + "&FileExtensions=" + TreePilotProperties.getString("ValidFileExtensions"));
+                               URLConnection conn = theServlet.openConnection();
+                               ObjectInputStream in = new ObjectInputStream(conn.getInputStream());
+                               String[] fileList = (String[]) in.readObject();
+                               FileDialog fileDialog = new FileDialog(this, ImageDir + TreePilotSystemID, fileList, "File Chooser", true);
+                               selectedFile = fileDialog.getSelectedFile();
+                               fileDialog.dispose();
+                               in.close();
+                       }
+                       catch (MalformedURLException mue)
+                       {
+                               System.err.println("MalFormedURLException during insertFile " + mue);
+                       }
+                       catch (IOException ie)
+                       {
+                               System.err.println("IOException during insertFile " + ie);
+                       }
+                       catch (ClassNotFoundException cnfe)
+                       {
+                               System.err.println("ClassNotFoundException during insertFile" + cnfe);
+                       }
+               }
+               return selectedFile;
+       }
+
+       /** Method for saving text as a complete HTML document
+         */
+       private void writeOut(HTMLDocument doc, File whatFile)
+       throws IOException, BadLocationException
+       {
+               if(whatFile == null)
+               {
+                       whatFile = getFileFromChooser(".", JFileChooser.SAVE_DIALOG, extsHTML, Translatrix.getTranslationString("FiletypeHTML"));
+               }
+               if(whatFile != null)
+               {
+                       FileWriter fw = new FileWriter(whatFile);
+                       htmlKit.write(fw, doc, 0, doc.getLength());
+                       fw.flush();
+                       fw.close();
+                       currentFile = whatFile;
+                       updateTitle();
+               }
+               refreshOnUpdate();
+       }
+
+       /** Method for saving text as an HTML fragment
+         */
+       private void writeOutFragment(HTMLDocument doc, String containingTag)
+       throws IOException, BadLocationException
+       {
+               File whatFile = getFileFromChooser(".", JFileChooser.SAVE_DIALOG, extsHTML, Translatrix.getTranslationString("FiletypeHTML"));
+               if(whatFile != null)
+               {
+                       FileWriter fw = new FileWriter(whatFile);
+//                     Element eleBody = locateElementInDocument((StyledDocument)doc, containingTag);
+//                     htmlKit.write(fw, doc, eleBody.getStartOffset(), eleBody.getEndOffset());
+                       String docTextCase = jtpSource.getText().toLowerCase();
+                       int tagStart       = docTextCase.indexOf("<" + containingTag.toLowerCase());
+                       int tagStartClose  = docTextCase.indexOf(">", tagStart) + 1;
+                       String closeTag    = "</" + containingTag.toLowerCase() + ">";
+                       int tagEndOpen     = docTextCase.indexOf(closeTag);
+                       if(tagStartClose < 0) { tagStartClose = 0; }
+                       if(tagEndOpen < 0 || tagEndOpen > docTextCase.length()) { tagEndOpen = docTextCase.length(); }
+                       String bodyText = jtpSource.getText().substring(tagStartClose, tagEndOpen);
+                       fw.write(bodyText, 0, bodyText.length());
+                       fw.flush();
+                       fw.close();
+               }
+               refreshOnUpdate();
+       }
+
+       /** Method for saving text as an RTF document
+         */
+       private void writeOutRTF(StyledDocument doc)
+       throws IOException, BadLocationException
+       {
+               File whatFile = getFileFromChooser(".", JFileChooser.SAVE_DIALOG, extsRTF, Translatrix.getTranslationString("FiletypeRTF"));
+               if(whatFile != null)
+               {
+                       FileOutputStream fos = new FileOutputStream(whatFile);
+                       RTFEditorKit rtfKit = new RTFEditorKit();
+                       rtfKit.write(fos, doc, 0, doc.getLength());
+                       fos.flush();
+                       fos.close();
+               }
+               refreshOnUpdate();
+       }
+
+       /** Method for saving text as a Base64 encoded document
+         */
+       private void writeOutBase64(String text)
+       throws IOException, BadLocationException
+       {
+               File whatFile = getFileFromChooser(".", JFileChooser.SAVE_DIALOG, extsB64, Translatrix.getTranslationString("FiletypeB64"));
+               if(whatFile != null)
+               {
+                       String base64text = Base64Codec.encode(text);
+                       FileWriter fw = new FileWriter(whatFile);
+                       fw.write(base64text, 0, base64text.length());
+                       fw.flush();
+                       fw.close();
+               }
+               refreshOnUpdate();
+       }
+
+       /** Method to invoke loading HTML into the app
+         */
+       private void openDocument(File whatFile)
+       throws IOException, BadLocationException
+       {
+               if(whatFile == null)
+               {
+                       whatFile = getFileFromChooser(".", JFileChooser.OPEN_DIALOG, extsHTML, Translatrix.getTranslationString("FiletypeHTML"));
+               }
+               if(whatFile != null)
+               {
+                       try
+                       {
+                               loadDocument(whatFile, null);
+                       }
+                       catch(ChangedCharSetException ccse)
+                       {
+                               String charsetType = ccse.getCharSetSpec().toLowerCase();
+                               int pos = charsetType.indexOf("charset");
+                               if(pos == -1)
+                               {
+                                       throw ccse;
+                               }
+                               while(pos < charsetType.length() && charsetType.charAt(pos) != '=')
+                               {
+                                       pos++;
+                               }
+                               pos++; // Places file cursor past the equals sign (=)
+                               String whatEncoding = charsetType.substring(pos).trim();
+                               loadDocument(whatFile, whatEncoding);
+                       }
+               }
+               refreshOnUpdate();
+       }
+
+       /** Method for loading HTML document into the app, including document encoding setting
+         */
+       private void loadDocument(File whatFile, String whatEncoding)
+       throws IOException, BadLocationException
+       {
+               Reader r = null;
+               htmlDoc = (ExtendedHTMLDocument)(htmlKit.createDefaultDocument());
+               try
+               {
+                       if(whatEncoding == null)
+                       {
+                               r = new InputStreamReader(new FileInputStream(whatFile));
+                       }
+                       else
+                       {
+                               r = new InputStreamReader(new FileInputStream(whatFile), whatEncoding);
+                               htmlDoc.putProperty("IgnoreCharsetDirective", new Boolean(true));
+                       }
+                       htmlKit.read(r, htmlDoc, 0);
+                       r.close();
+                       registerDocument(htmlDoc);
+                       jtpSource.setText(jtpMain.getText());
+                       currentFile = whatFile;
+                       updateTitle();
+               }
+               finally
+               {
+                       if(r != null)
+                       {
+                               r.close();
+                       }
+               }
+       }
+
+       /** Method for loading a Base64 encoded document
+         */
+       private void openDocumentBase64(File whatFile)
+       throws IOException, BadLocationException
+       {
+               if(whatFile == null)
+               {
+                       whatFile = getFileFromChooser(".", JFileChooser.OPEN_DIALOG, extsB64, Translatrix.getTranslationString("FiletypeB64"));
+               }
+               if(whatFile != null)
+               {
+                       FileReader fr = new FileReader(whatFile);
+                       int nextChar = 0;
+                       StringBuffer encodedText = new StringBuffer();
+                       try
+                       {
+                               while((nextChar = fr.read()) != -1)
+                               {
+                                       encodedText.append((char)nextChar);
+                               }
+                               fr.close();
+                               jtpSource.setText(Base64Codec.decode(encodedText.toString()));
+                               jtpMain.setText(jtpSource.getText());
+                               registerDocument((ExtendedHTMLDocument)(jtpMain.getDocument()));
+                       }
+                       finally
+                       {
+                               if(fr != null)
+                               {
+                                       fr.close();
+                               }
+                       }
+               }
+       }
+
+       /** Method for loading a Stylesheet into the app
+         */
+       private void openStyleSheet(File fileCSS)
+       throws IOException
+       {
+               if(fileCSS == null)
+               {
+                       fileCSS = getFileFromChooser(".", JFileChooser.OPEN_DIALOG, extsCSS, Translatrix.getTranslationString("FiletypeCSS"));
+               }
+               if(fileCSS != null)
+               {
+                       String currDocText = jtpMain.getText();
+                       htmlDoc = (ExtendedHTMLDocument)(htmlKit.createDefaultDocument());
+                       styleSheet = htmlDoc.getStyleSheet();
+                       URL cssUrl = fileCSS.toURL();
+                       InputStream is = cssUrl.openStream();
+                       BufferedReader br = new BufferedReader(new InputStreamReader(is));
+                       styleSheet.loadRules(br, cssUrl);
+                       br.close();
+                       htmlDoc = new ExtendedHTMLDocument(styleSheet);
+                       registerDocument(htmlDoc);
+                       jtpMain.setText(currDocText);
+                       jtpSource.setText(jtpMain.getText());
+               }
+               refreshOnUpdate();
+       }
+
+       /** Method for serializing the document out to a file
+         */
+       public void serializeOut(HTMLDocument doc)
+       throws IOException
+       {
+               File whatFile = getFileFromChooser(".", JFileChooser.SAVE_DIALOG, extsSer, Translatrix.getTranslationString("FiletypeSer"));
+               if(whatFile != null)
+               {
+                       ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(whatFile));
+                       oos.writeObject(doc);
+                       oos.flush();
+                       oos.close();
+               }
+               refreshOnUpdate();
+       }
+
+       /** Method for reading in a serialized document from a file
+         */
+       public void serializeIn()
+       throws IOException, ClassNotFoundException
+       {
+               File whatFile = getFileFromChooser(".", JFileChooser.OPEN_DIALOG, extsSer, Translatrix.getTranslationString("FiletypeSer"));
+               if(whatFile != null)
+               {
+                       ObjectInputStream ois = new ObjectInputStream(new FileInputStream(whatFile));
+                       htmlDoc = (ExtendedHTMLDocument)(ois.readObject());
+                       ois.close();
+                       registerDocument(htmlDoc);
+                       validate();
+               }
+               refreshOnUpdate();
+       }
+
+       /** Method for obtaining a File for input/output using a JFileChooser dialog
+         */
+       private File getFileFromChooser(String startDir, int dialogType, String[] exts, String desc)
+       {
+               JFileChooser jfileDialog = new JFileChooser(startDir);
+               jfileDialog.setDialogType(dialogType);
+               jfileDialog.setFileFilter(new MutableFilter(exts, desc));
+               int optionSelected = JFileChooser.CANCEL_OPTION;
+               if(dialogType == JFileChooser.OPEN_DIALOG)
+               {
+                       optionSelected = jfileDialog.showOpenDialog(this);
+               }
+               else if(dialogType == JFileChooser.SAVE_DIALOG)
+               {
+                       optionSelected = jfileDialog.showSaveDialog(this);
+               }
+               else // default to an OPEN_DIALOG
+               {
+                       optionSelected = jfileDialog.showOpenDialog(this);
+               }
+               if(optionSelected == JFileChooser.APPROVE_OPTION)
+               {
+                       return jfileDialog.getSelectedFile();
+               }
+               return (File)null;
+       }
+
+       /** Method for obtaining an Image for input using a custom JFileChooser dialog
+         */
+       private File getImageFromChooser(String startDir, String[] exts, String desc)
+       {
+               ImageFileChooser jImageDialog = new ImageFileChooser(startDir);
+               jImageDialog.setDialogType(JFileChooser.CUSTOM_DIALOG);
+               jImageDialog.setFileFilter(new MutableFilter(exts, desc));
+               jImageDialog.setDialogTitle(Translatrix.getTranslationString("ImageDialogTitle"));
+               int optionSelected = JFileChooser.CANCEL_OPTION;
+               optionSelected = jImageDialog.showDialog(this, Translatrix.getTranslationString("Insert"));
+               if(optionSelected == JFileChooser.APPROVE_OPTION)
+               {
+                       return jImageDialog.getSelectedFile();
+               }
+               return (File)null;
+       }
+
+       /** Method for describing the node hierarchy of the document
+         */
+       private void describeDocument(StyledDocument doc)
+       {
+               Element[] elements = doc.getRootElements();
+               for(int i = 0; i < elements.length; i++)
+               {
+                       indent = indentStep;
+                       for(int j = 0; j < indent; j++) { System.out.print(" "); }
+                       System.out.print(elements[i]);
+                       traverseElement(elements[i]);
+                       System.out.println("");
+               }
+       }
+
+       /** Traverses nodes for the describing method
+         */
+       private void traverseElement(Element element)
+       {
+               indent += indentStep;
+               for(int i = 0; i < element.getElementCount(); i++)
+               {
+                       for(int j = 0; j < indent; j++) { System.out.print(" "); }
+                       System.out.print(element.getElement(i));
+                       traverseElement(element.getElement(i));
+               }
+               indent -= indentStep;
+       }
+
+       /** Method to locate a node element by name
+         */
+       private Element locateElementInDocument(StyledDocument doc, String elementName)
+       {
+               Element[] elements = doc.getRootElements();
+               for(int i = 0; i < elements.length; i++)
+               {
+                       if(elements[i].getName().equalsIgnoreCase(elementName))
+                       {
+                               return elements[i];
+                       }
+                       else
+                       {
+                               Element rtnElement = locateChildElementInDocument(elements[i], elementName);
+                               if(rtnElement != null)
+                               {
+                                       return rtnElement;
+                               }
+                       }
+               }
+               return (Element)null;
+       }
+
+       /** Traverses nodes for the locating method
+         */
+       private Element locateChildElementInDocument(Element element, String elementName)
+       {
+               for(int i = 0; i < element.getElementCount(); i++)
+               {
+                       if(element.getElement(i).getName().equalsIgnoreCase(elementName))
+                       {
+                               return element.getElement(i);
+                       }
+               }
+               return (Element)null;
+       }
+
+       /** Convenience method for obtaining the WYSIWYG JTextPane
+         */
+       public JTextPane getTextPane()
+       {
+               return jtpMain;
+       }
+
+       /** Convenience method for obtaining the Source JTextPane
+         */
+       public JTextPane getSourcePane()
+       {
+               return jtpSource;
+       }
+
+       /** Convenience method for obtaining the application as a Frame
+         */
+       public Frame getFrame()
+       {
+               return frameHandler;
+       }
+
+       /** Convenience method for setting the parent Frame
+         */
+       public void setFrame(Frame parentFrame)
+       {
+               frameHandler = parentFrame;
+       }
+
+       /** Convenience method for obtaining the pre-generated menu bar
+         */
+       public JMenuBar getMenuBar()
+       {
+               return jMenuBar;
+       }
+
+       /** Convenience method for obtaining a custom menu bar
+         */
+       public JMenuBar getCustomMenuBar(Vector vcMenus)
+       {
+               jMenuBar = new JMenuBar();
+               for(int i = 0; i < vcMenus.size(); i++)
+               {
+                       String menuToAdd = ((String)(vcMenus.elementAt(i))).toLowerCase();
+                       if(htMenus.containsKey(menuToAdd))
+                       {
+                               jMenuBar.add((JMenu)(htMenus.get(menuToAdd)));
+                       }
+               }
+               return jMenuBar;
+       }
+
+       /** Convenience method for obtaining the pre-generated toolbar
+         */
+       public JToolBar getToolBar(boolean isShowing)
+       {
+               jcbmiViewToolbar.setState(isShowing);
+               return jToolBar;
+       }
+
+       /** Convenience method for obtaining the pre-generated toolbar
+         */
+       public JToolBar getCustomToolBar(Vector vcTools, boolean isShowing)
+       {
+               jcbmiViewToolbar.setState(isShowing);
+               jToolBar = new JToolBar(JToolBar.HORIZONTAL);
+               jToolBar.setFloatable(false);
+               for(int i = 0; i < vcTools.size(); i++)
+               {
+                       String toolToAdd = ((String)(vcTools.elementAt(i))).toLowerCase();
+                       if(toolToAdd.equals(KEY_TOOL_SEP))
+                       {
+                               jToolBar.add(new JToolBar.Separator());
+                       }
+                       else if(htTools.containsKey(toolToAdd))
+                       {
+                               if(htTools.get(toolToAdd) instanceof JButtonNoFocus)
+                               {
+                                       jToolBar.add((JButtonNoFocus)(htTools.get(toolToAdd)));
+                               }
+                               else if(htTools.get(toolToAdd) instanceof JToggleButtonNoFocus)
+                               {
+                                       jToolBar.add((JToggleButtonNoFocus)(htTools.get(toolToAdd)));
+                               }
+                               else if(htTools.get(toolToAdd) instanceof JComboBoxNoFocus)
+                               {
+                                       jToolBar.add((JComboBoxNoFocus)(htTools.get(toolToAdd)));
+                               }
+                               else
+                               {
+                                       jToolBar.add((JComponent)(htTools.get(toolToAdd)));
+                               }
+                       }
+               }
+               return jToolBar;
+       }
+
+       /** Convenience method for obtaining the current file handle
+         */
+       public File getCurrentFile()
+       {
+               return currentFile;
+       }
+
+       /** Convenience method for obtaining the application name
+         */
+       public String getAppName()
+       {
+               return appName;
+       }
+
+       /** Convenience method for obtaining the document text
+         */
+       public String getDocumentText()
+       {
+               return jtpMain.getText();
+       }
+
+       /** Convenience method for obtaining the document text
+         * contained within a tag pair
+         */
+       public String getDocumentSubText(String tagBlock)
+       {
+               return getSubText(tagBlock);
+       }
+
+       /** Method for extracting the text within a tag
+         */
+       private String getSubText(String containingTag)
+       {
+               jtpSource.setText(jtpMain.getText());
+               String docTextCase = jtpSource.getText().toLowerCase();
+               int tagStart       = docTextCase.indexOf("<" + containingTag.toLowerCase());
+               int tagStartClose  = docTextCase.indexOf(">", tagStart) + 1;
+               String closeTag    = "</" + containingTag.toLowerCase() + ">";
+               int tagEndOpen     = docTextCase.indexOf(closeTag);
+               if(tagStartClose < 0) { tagStartClose = 0; }
+               if(tagEndOpen < 0 || tagEndOpen > docTextCase.length()) { tagEndOpen = docTextCase.length(); }
+               return jtpSource.getText().substring(tagStartClose, tagEndOpen);
+       }
+
+       /** Convenience method for obtaining the document text
+               * contained within the BODY tags (a common request)
+         */
+       public String getDocumentBody()
+       {
+               return getSubText("body");
+       }
+
+       /** Convenience method for setting the document text
+         */
+       public void setDocumentText(String sText)
+       {
+               jtpMain.setText(sText);
+               ((HTMLEditorKit)(jtpMain.getEditorKit())).setDefaultCursor(new Cursor(Cursor.TEXT_CURSOR));
+               jtpSource.setText(jtpMain.getText());
+               ((HTMLEditorKit)(jtpSource.getEditorKit())).setDefaultCursor(new Cursor(Cursor.TEXT_CURSOR));
+       }
+
+       /** Convenience method for obtaining the document text
+         */
+       private void updateTitle()
+       {
+               frameHandler.setTitle(appName + (currentFile == null ? "" : " - " + currentFile.getName()));
+       }
+
+       /** Convenience method for clearing out the UndoManager
+         */
+       public void purgeUndos()
+       {
+               if(undoMngr != null)
+               {
+                       undoMngr.discardAllEdits();
+                       undoAction.updateUndoState();
+                       redoAction.updateRedoState();
+               }
+       }
+
+       /** Convenience method for refreshing and displaying changes
+         */
+       public void refreshOnUpdate()
+       {
+               jtpMain.setText(jtpMain.getText());
+               jtpSource.setText(jtpMain.getText());
+               purgeUndos();
+               this.repaint();
+       }
+
+       /** Convenience method for deallocating the app resources
+         */
+       public void dispose()
+       {
+               frameHandler.dispose();
+               System.exit(0);
+       }
+
+       /** Convenience method for fetching icon images from jar file
+         */
+       private ImageIcon getEkitIcon(String iconName)
+       {
+               return new ImageIcon(Toolkit.getDefaultToolkit().getImage(getClass().getResource("icons/" + iconName + "HK.gif")));
+       }
+
+       /** Convenience method for outputting exceptions
+         */
+       private void logException(String internalMessage, Exception e)
+       {
+               System.err.println(internalMessage);
+               e.printStackTrace(System.err);
+       }
+
+       /** Convenience method for toggling source window visibility
+         */
+       private void toggleSourceWindow()
+       {
+               if(!(jspSource.isShowing()))
+               {
+                       jtpSource.setText(jtpMain.getText());
+                       jspltDisplay.setRightComponent(jspSource);
+                       if(exclusiveEdit)
+                       {
+                               jspltDisplay.setDividerLocation(0);
+                               jspltDisplay.setEnabled(false);
+                       }
+                       else
+                       {
+                               jspltDisplay.setDividerLocation(iSplitPos);
+                               jspltDisplay.setEnabled(true);
+                       }
+               }
+               else
+               {
+                       jtpMain.setText(jtpSource.getText());
+                       iSplitPos = jspltDisplay.getDividerLocation();
+                       jspltDisplay.remove(jspSource);
+                       jtpMain.requestFocus();
+               }
+               this.validate();
+               jcbmiViewSource.setSelected(jspSource.isShowing());
+               jtbtnViewSource.setSelected(jspSource.isShowing());
+       }
+
+       /** Searches the specified element for CLASS attribute setting
+         */
+       private String findStyle(Element element)
+       {
+               AttributeSet as = element.getAttributes();
+               if(as == null)
+               {
+                       return null;
+               }
+               Object val = as.getAttribute(HTML.Attribute.CLASS);
+               if(val != null && (val instanceof String))
+               {
+                       return (String)val;
+               }
+               for(Enumeration e = as.getAttributeNames(); e.hasMoreElements();)
+               {
+                       Object key = e.nextElement();
+                       if(key instanceof HTML.Tag)
+                       {
+                               AttributeSet eas = (AttributeSet)(as.getAttribute(key));
+                               if(eas != null)
+                               {
+                                       val = eas.getAttribute(HTML.Attribute.CLASS);
+                                       if(val != null)
+                                       {
+                                               return (String)val;
+                                       }
+                               }
+                       }
+
+               }
+               return null;
+       }
+
+       /** Handles caret tracking and related events, such as displaying the current style
+         * of the text under the caret
+         */
+       private void handleCaretPositionChange(CaretEvent ce)
+       {
+               int caretPos = ce.getDot();
+               Element element = htmlDoc.getCharacterElement(caretPos);
+/*
+---- TAG EXPLICATOR CODE -------------------------------------------
+               javax.swing.text.ElementIterator ei = new javax.swing.text.ElementIterator(htmlDoc);
+               Element ele;
+               while((ele = ei.next()) != null)
+               {
+                       System.out.println("ELEMENT : " + ele.getName());
+               }
+               System.out.println("ELEMENT:" + element.getName());
+               Element elementParent = element.getParentElement();
+               System.out.println("ATTRS:");
+               AttributeSet attribs = elementParent.getAttributes();
+               for(Enumeration eAttrs = attribs.getAttributeNames(); eAttrs.hasMoreElements();)
+               {
+                       System.out.println("  " + eAttrs.nextElement().toString());
+               }
+               while(elementParent != null && !elementParent.getName().equals("body"))
+               {
+                       String parentName = elementParent.getName();
+                       System.out.println("PARENT:" + parentName);
+                       System.out.println("ATTRS:");
+                       attribs = elementParent.getAttributes();
+                       for(Enumeration eAttr = attribs.getAttributeNames(); eAttr.hasMoreElements();)
+                       {
+                               System.out.println("  " + eAttr.nextElement().toString());
+                       }
+                       elementParent = elementParent.getParentElement();
+               }
+---- END -------------------------------------------
+*/
+               if(element == null)
+               {
+                       return;
+               }
+               String style = null;
+               Vector vcStyles = new Vector();
+               while(element != null)
+               {
+                       if(style == null)
+                       {
+                               style = findStyle(element);
+                       }
+                       vcStyles.add(element);
+                       element = element.getParentElement();
+               }
+               int stylefound = -1;
+               if(style != null)
+               {
+                       for(int i = 0; i < jcmbStyleSelector.getItemCount(); i++)
+                       {
+                               String in = (String)(jcmbStyleSelector.getItemAt(i));
+                               if(in.equalsIgnoreCase(style))
+                               {
+                                       stylefound = i;
+                                       break;
+                               }
+                       }
+               }
+               if(stylefound > -1)
+               {
+                       Action ac = jcmbStyleSelector.getAction();
+                       ac.setEnabled(false);
+                       jcmbStyleSelector.setSelectedIndex(stylefound);
+                       ac.setEnabled(true);
+               }
+               else
+               {
+                       jcmbStyleSelector.setSelectedIndex(0);
+               }
+       }
+
+       /** Server-side image handling methods
+         */
+       protected void setServletURL(String url)
+       {
+               ServletURL = url;
+       }
+
+       protected void setImageDir(String sysDir)
+       {
+               ImageDir = sysDir;
+       }
+
+       public void setTreePilotSystemID(String theSystem)
+       {
+               TreePilotSystemID = theSystem;
+       }
+
+       /** Utility methods
+         */
+       public ExtendedHTMLDocument getExtendedHtmlDoc()
+       {
+               return (ExtendedHTMLDocument)htmlDoc;
+       }
+
+       public int getCaretPosition()
+       {
+               return jtpMain.getCaretPosition();
+       }
+
+       public void setCaretPosition(int newPositon)
+       {
+               boolean end = true;
+               do
+               {
+                       end = true;
+                       try
+                       {
+                               jtpMain.setCaretPosition(newPositon);
+                       }
+                       catch (IllegalArgumentException iae)
+                       {
+                               end = false;
+                               newPositon--;
+                       }
+               } while(!end && newPositon >= 0);
+       }
+
+/* Inner Classes --------------------------------------------- */
+
+       /** Class for implementing Undo as an autonomous action
+         */
+       class UndoAction extends AbstractAction
+       {
+               public UndoAction()
+               {
+                       super(Translatrix.getTranslationString("Undo"));
+                       setEnabled(false);
+               }
+
+               public void actionPerformed(ActionEvent e)
+               {
+                       try
+                       {
+                               undoMngr.undo();
+                       }
+                       catch(CannotUndoException ex)
+                       {
+                               ex.printStackTrace();
+                       }
+                       updateUndoState();
+                       redoAction.updateRedoState();
+               }
+
+               protected void updateUndoState()
+               {
+                       if(undoMngr.canUndo())
+                       {
+                               setEnabled(true);
+                               putValue(Action.NAME, undoMngr.getUndoPresentationName());
+                       }
+                       else
+                       {
+                               setEnabled(false);
+                               putValue(Action.NAME, Translatrix.getTranslationString("Undo"));
+                       }
+               }
+       }
+
+       /** Class for implementing Redo as an autonomous action
+         */
+       class RedoAction extends AbstractAction
+       {
+               public RedoAction()
+               {
+                       super(Translatrix.getTranslationString("Redo"));
+                       setEnabled(false);
+               }
+
+               public void actionPerformed(ActionEvent e)
+               {
+                       try
+                       {
+                               undoMngr.redo();
+                       }
+                       catch(CannotUndoException ex)
+                       {
+                               ex.printStackTrace();
+                       }
+                       updateRedoState();
+                       undoAction.updateUndoState();
+               }
+
+               protected void updateRedoState()
+               {
+                       if(undoMngr.canRedo())
+                       {
+                               setEnabled(true);
+                               putValue(Action.NAME, undoMngr.getRedoPresentationName());
+                       }
+                       else
+                       {
+                               setEnabled(false);
+                               putValue(Action.NAME, Translatrix.getTranslationString("Redo"));
+                       }
+               }
+       }
+
+       /** Class for implementing the Undo listener to handle the Undo and Redo actions
+         */
+       class CustomUndoableEditListener implements UndoableEditListener
+       {
+               public void undoableEditHappened(UndoableEditEvent uee)
+               {
+                       undoMngr.addEdit(uee.getEdit());
+                       undoAction.updateUndoState();
+                       redoAction.updateRedoState();
+               }
+       }
+
+}
diff --git a/ekit/com/hexidec/ekit/EkitCore_Basic.java b/ekit/com/hexidec/ekit/EkitCore_Basic.java
new file mode 100644 (file)
index 0000000..ef23e15
--- /dev/null
@@ -0,0 +1,2836 @@
+/*
+GNU Lesser General Public License
+
+EkitCore - Base Java Swing HTML Editor & Viewer Class (Basic Version)
+Copyright (C) 2000-2003 Howard Kistler
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+package com.hexidec.ekit;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Cursor;
+import java.awt.Dimension;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.Image;
+import java.awt.Insets;
+import java.awt.Toolkit;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Reader;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.MalformedURLException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+import java.util.Vector;
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+import javax.swing.JDialog;
+import javax.swing.JEditorPane;
+import javax.swing.JFileChooser;
+import javax.swing.JFrame;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSplitPane;
+import javax.swing.JTextField;
+import javax.swing.JTextPane;
+import javax.swing.JToggleButton;
+import javax.swing.JToolBar;
+import javax.swing.KeyStroke;
+import javax.swing.event.CaretEvent;
+import javax.swing.event.CaretListener;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import javax.swing.event.UndoableEditEvent;
+import javax.swing.event.UndoableEditListener;
+import javax.swing.filechooser.FileFilter;
+import javax.swing.text.AttributeSet;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.ChangedCharSetException;
+import javax.swing.text.DefaultEditorKit;
+import javax.swing.text.DefaultStyledDocument;
+import javax.swing.text.Document;
+import javax.swing.text.Element;
+import javax.swing.text.PlainDocument;
+import javax.swing.text.Position;
+import javax.swing.text.Style;
+import javax.swing.text.StyleConstants;
+import javax.swing.text.StyledDocument;
+import javax.swing.text.StyledEditorKit;
+import javax.swing.text.StyledEditorKit.FontSizeAction;
+import javax.swing.text.html.HTML;
+import javax.swing.text.html.HTMLDocument;
+import javax.swing.text.html.HTMLEditorKit;
+import javax.swing.text.html.StyleSheet;
+import javax.swing.text.rtf.RTFEditorKit;
+import javax.swing.undo.UndoManager;
+import javax.swing.undo.CannotUndoException;
+
+import com.hexidec.ekit.action.*;
+import com.hexidec.ekit.component.*;
+import com.hexidec.util.Base64Codec;
+import com.hexidec.util.Translatrix;
+
+/** EkitCore
+  * Main application class for editing and saving HTML in a Java text component
+  *
+  * @author Howard Kistler
+  * @version 0.9g
+  *
+  * REQUIREMENTS
+  * Java 2 (JDK 1.3 or 1.4)
+  * Swing Library
+  */
+
+public class EkitCore extends JPanel implements ActionListener, KeyListener, DocumentListener
+{
+       /* Components */
+       private JSplitPane jspltDisplay;
+       private JTextPane jtpMain;
+       private ExtendedHTMLEditorKit htmlKit;
+       private ExtendedHTMLDocument htmlDoc;
+       private StyleSheet styleSheet;
+       private JTextPane jtpSource;
+       private JScrollPane jspSource;
+       private JToolBar jToolBar;
+
+       private JCheckBoxMenuItem jcbmiViewToolbar;
+       private JCheckBoxMenuItem jcbmiViewSource;
+
+       private JButtonNoFocus jbtnNewHTML;
+       private JButtonNoFocus jbtnOpenHTML;
+       private JButtonNoFocus jbtnSaveHTML;
+       private JButtonNoFocus jbtnCut;
+       private JButtonNoFocus jbtnCopy;
+       private JButtonNoFocus jbtnPaste;
+       private JButtonNoFocus jbtnBold;
+       private JButtonNoFocus jbtnItalic;
+       private JButtonNoFocus jbtnUnderline;
+       private JButtonNoFocus jbtnStrike;
+       private JButtonNoFocus jbtnSuperscript;
+       private JButtonNoFocus jbtnSubscript;
+       private JButtonNoFocus jbtnUList;
+       private JButtonNoFocus jbtnOList;
+       private JButtonNoFocus jbtnClearFormat;
+       private JButtonNoFocus jbtnAnchor;
+       private JToggleButtonNoFocus jtbtnViewSource;
+       private JComboBoxNoFocus jcmbStyleSelector;
+
+       private Frame frameHandler;
+
+       private HTMLUtilities htmlUtilities = new HTMLUtilities(this);
+
+       /* Actions */
+       private StyledEditorKit.BoldAction actionFontBold;
+       private StyledEditorKit.ItalicAction actionFontItalic;
+       private StyledEditorKit.UnderlineAction actionFontUnderline;
+       private FormatAction actionFontStrike;
+       private FormatAction actionFontSuperscript;
+       private FormatAction actionFontSubscript;
+       private ListAutomationAction actionListUnordered;
+       private ListAutomationAction actionListOrdered;
+       private CustomAction actionSelectFont;
+       private CustomAction actionClearFormat;
+       private CustomAction actionInsertAnchor;
+
+       protected UndoManager undoMngr;
+       protected UndoAction undoAction;
+       protected RedoAction redoAction;
+
+       /* Menus */
+       private JMenuBar jMenuBar;
+       private JMenu jMenuFile;
+       private JMenu jMenuEdit;
+       private JMenu jMenuView;
+       private JMenu jMenuFont;
+       private JMenu jMenuFormat;
+       private JMenu jMenuInsert;
+       private JMenu jMenuTable;
+       private JMenu jMenuForms;
+       private JMenu jMenuSearch;
+       private JMenu jMenuHelp;
+       private JMenu jMenuDebug;
+
+       /* Constants */
+       // Menu Keys
+       public static final String KEY_MENU_FILE   = "file";
+       public static final String KEY_MENU_EDIT   = "edit";
+       public static final String KEY_MENU_VIEW   = "view";
+       public static final String KEY_MENU_FONT   = "font";
+       public static final String KEY_MENU_FORMAT = "format";
+       public static final String KEY_MENU_INSERT = "insert";
+       public static final String KEY_MENU_TABLE  = "table";
+       public static final String KEY_MENU_FORMS  = "forms";
+       public static final String KEY_MENU_SEARCH = "search";
+       public static final String KEY_MENU_TOOLS  = "tools";
+       public static final String KEY_MENU_HELP   = "help";
+       public static final String KEY_MENU_DEBUG  = "debug";
+
+       // Tool Keys
+       public static final String KEY_TOOL_SEP       = "separator";
+       public static final String KEY_TOOL_NEW       = "new";
+       public static final String KEY_TOOL_OPEN      = "open";
+       public static final String KEY_TOOL_SAVE      = "save";
+       public static final String KEY_TOOL_CUT       = "cut";
+       public static final String KEY_TOOL_COPY      = "copy";
+       public static final String KEY_TOOL_PASTE     = "paste";
+       public static final String KEY_TOOL_BOLD      = "bold";
+       public static final String KEY_TOOL_ITALIC    = "italic";
+       public static final String KEY_TOOL_UNDERLINE = "underline";
+       public static final String KEY_TOOL_STRIKE    = "strike";
+       public static final String KEY_TOOL_SUPER     = "superscript";
+       public static final String KEY_TOOL_SUB       = "subscript";
+       public static final String KEY_TOOL_ULIST     = "ulist";
+       public static final String KEY_TOOL_OLIST     = "olist";
+       public static final String KEY_TOOL_CLEAR     = "clearformats";
+       public static final String KEY_TOOL_ANCHOR    = "anchor";
+       public static final String KEY_TOOL_SOURCE    = "viewsource";
+       public static final String KEY_TOOL_STYLES    = "styleselect";
+
+       // Menu & Tool Key Arrays
+       private static Hashtable htMenus = new Hashtable();
+       private static Hashtable htTools = new Hashtable();
+
+       private final String appName = "Ekit";
+       private final String menuDialog = "..."; /* text to append to a MenuItem label when menu item opens a dialog */
+
+       private final boolean useFormIndicator = true; /* Creates a highlighted background on a new FORM so that it may be more easily edited */
+       private final String clrFormIndicator = "#cccccc";
+
+       // System Clipboard Settings
+       private java.awt.datatransfer.Clipboard sysClipboard;
+       private SecurityManager secManager;
+
+       /* Variables */
+       private int iSplitPos = 0;
+
+       private boolean exclusiveEdit = true;
+
+       private String lastSearchFindTerm     = null;
+       private String lastSearchReplaceTerm  = null;
+       private boolean lastSearchCaseSetting = false;
+       private boolean lastSearchTopSetting  = false;
+
+       private File currentFile = null;
+
+       private int indent = 0;
+       private final int indentStep = 4;
+
+       // File extensions for MutableFilter
+       private final String[] extsHTML = { "html", "htm", "shtml" };
+       private final String[] extsCSS  = { "css" };
+       private final String[] extsIMG  = { "gif", "jpg", "jpeg", "png" };
+       private final String[] extsRTF  = { "rtf" };
+       private final String[] extsB64  = { "b64" };
+       private final String[] extsSer  = { "ser" };
+
+       /* Servlet Settings */
+       private String ServletURL = null;
+       private String TreePilotSystemID = "";
+       private String ImageDir = "";
+       private static ResourceBundle TreePilotProperties;
+
+       /** Master Constructor
+         * @param sDocument         [String]  A text or HTML document to load in the editor upon startup.
+         * @param sStyleSheet       [String]  A CSS stylesheet to load in the editor upon startup.
+         * @param sRawDocument      [String]  A document encoded as a String to load in the editor upon startup.
+         * @param urlStyleSheet     [URL]     A URL reference to the CSS style sheet.
+         * @param showViewSource    [boolean] Specifies whether or not to show the View Source window on startup.
+         * @param showMenuIcons     [boolean] Specifies whether or not to show icon pictures in menus.
+         * @param editModeExclusive [boolean] Specifies whether or not to use exclusive edit mode (recommended on).
+         * @param sLanguage         [String]  The language portion of the Internationalization Locale to run Ekit in.
+         * @param sCountry          [String]  The country portion of the Internationalization Locale to run Ekit in.
+         * @param base64            [boolean] Specifies whether the raw document is Base64 encoded or not.
+         * @param debugMode         [boolean] Specifies whether to show the Debug menu or not.
+         */
+       public EkitCore(String sDocument, String sStyleSheet, String sRawDocument, URL urlStyleSheet, boolean showViewSource, boolean showMenuIcons, boolean editModeExclusive, String sLanguage, String sCountry, boolean base64, boolean debugMode)
+       {
+               super();
+
+               exclusiveEdit = editModeExclusive;
+
+               frameHandler = new Frame();
+
+               // Determine if system clipboard is available
+               secManager = System.getSecurityManager();
+               if(secManager != null)
+               {
+                       try
+                       {
+                               secManager.checkSystemClipboardAccess();
+                               sysClipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
+                       }
+                       catch (SecurityException se)
+                       {
+                               sysClipboard = null;
+                       }
+               }
+
+               /* Localize for language */
+               Translatrix.setBundleName("com.hexidec.ekit.LanguageResources");
+               Locale baseLocale = (Locale)null;
+               if(sLanguage != null && sCountry != null)
+               {
+                       baseLocale = new Locale(sLanguage, sCountry);
+               }
+               Translatrix.setLocale(baseLocale);
+
+               /* Load TreePilot properties */
+               try
+               {
+                       TreePilotProperties = ResourceBundle.getBundle("com.hexidec.ekit.TreePilot");
+               }
+               catch(MissingResourceException mre)
+               {
+                       logException("MissingResourceException while loading treepilot file", mre);
+               }
+
+               /* Create the editor kit, document, and stylesheet */
+               jtpMain = new JTextPane();
+               htmlKit = new ExtendedHTMLEditorKit();
+               htmlDoc = (ExtendedHTMLDocument)(htmlKit.createDefaultDocument());
+               styleSheet = htmlDoc.getStyleSheet();
+               htmlKit.setDefaultCursor(new Cursor(Cursor.TEXT_CURSOR));
+
+               /* Set up the text pane */
+               jtpMain.setEditorKit(htmlKit);
+               jtpMain.setDocument(htmlDoc);
+               jtpMain.setMargin(new Insets(4, 4, 4, 4));
+               jtpMain.addKeyListener(this);
+
+               /* Create the source text area */
+               jtpSource = new JTextPane();
+               jtpSource.setBackground(new Color(212, 212, 212));
+               jtpSource.setSelectionColor(new Color(255, 192, 192));
+               jtpSource.setText(jtpMain.getText());
+               jtpSource.getDocument().addDocumentListener(this);
+
+               /* Add CaretListener for tracking caret location events */
+               jtpMain.addCaretListener(new CaretListener()
+               {
+                       public void caretUpdate(CaretEvent ce)
+                       {
+                               handleCaretPositionChange(ce);
+                       }
+               });
+
+               /* Set up the undo features */
+               undoMngr = new UndoManager();
+               undoAction = new UndoAction();
+               redoAction = new RedoAction();
+               jtpMain.getDocument().addUndoableEditListener(new CustomUndoableEditListener());
+
+               /* Insert raw document, if exists */
+               if(sRawDocument != null && sRawDocument.length() > 0)
+               {
+                       if(base64)
+                       {
+                               jtpMain.setText(Base64Codec.decode(sRawDocument));
+                       }
+                       else
+                       {
+                               jtpMain.setText(sRawDocument);
+                       }
+               }
+               jtpMain.setCaretPosition(0);
+               jtpMain.getDocument().addDocumentListener(this);
+
+               /* Import CSS from reference, if exists */
+               if(urlStyleSheet != null)
+               {
+                       try
+                       {
+                               String currDocText = jtpMain.getText();
+                               htmlDoc = (ExtendedHTMLDocument)(htmlKit.createDefaultDocument());
+                               styleSheet = htmlDoc.getStyleSheet();
+                               BufferedReader br = new BufferedReader(new InputStreamReader(urlStyleSheet.openStream()));
+                               styleSheet.loadRules(br, urlStyleSheet);
+                               br.close();
+                               htmlDoc = new ExtendedHTMLDocument(styleSheet);
+                               registerDocument(htmlDoc);
+                               jtpMain.setText(currDocText);
+                               jtpSource.setText(jtpMain.getText());
+                       }
+                       catch(Exception e)
+                       {
+                               e.printStackTrace(System.out);
+                       }
+               }
+
+               /* Preload the specified HTML document, if exists */
+               if(sDocument != null)
+               {
+                       File defHTML = new File(sDocument);
+                       if(defHTML.exists())
+                       {
+                               try
+                               {
+                                       openDocument(defHTML);
+                               }
+                               catch(Exception e)
+                               {
+                                       logException("Exception in preloading HTML document", e);
+                               }
+                       }
+               }
+
+               /* Preload the specified CSS document, if exists */
+               if(sStyleSheet != null)
+               {
+                       File defCSS = new File(sStyleSheet);
+                       if(defCSS.exists())
+                       {
+                               try
+                               {
+                                       openStyleSheet(defCSS);
+                               }
+                               catch(Exception e)
+                               {
+                                       logException("Exception in preloading CSS stylesheet", e);
+                               }
+                       }
+               }
+
+               /* Collect the actions that the JTextPane is naturally aware of */
+               Hashtable actions = new Hashtable();
+               Action[] actionsArray = jtpMain.getActions();
+               for(int i = 0; i < actionsArray.length; i++)
+               {
+                       Action a = actionsArray[i];
+                       actions.put(a.getValue(Action.NAME), a);
+               }
+
+               /* Create shared actions */
+               actionFontBold        = new StyledEditorKit.BoldAction();
+               actionFontItalic      = new StyledEditorKit.ItalicAction();
+               actionFontUnderline   = new StyledEditorKit.UnderlineAction();
+               actionFontStrike      = new FormatAction(this, Translatrix.getTranslationString("FontStrike"), HTML.Tag.STRIKE);
+               actionFontSuperscript = new FormatAction(this, Translatrix.getTranslationString("FontSuperscript"), HTML.Tag.SUP);
+               actionFontSubscript   = new FormatAction(this, Translatrix.getTranslationString("FontSubscript"), HTML.Tag.SUB);
+               actionListUnordered   = new ListAutomationAction(this, Translatrix.getTranslationString("ListUnordered"), HTML.Tag.UL);
+               actionListOrdered     = new ListAutomationAction(this, Translatrix.getTranslationString("ListOrdered"), HTML.Tag.OL);
+               Hashtable customAttr = new Hashtable();
+               customAttr.put("face","");
+               actionSelectFont      = new CustomAction(this, Translatrix.getTranslationString("FontSelect") + menuDialog, HTML.Tag.FONT, customAttr);
+               actionClearFormat     = new CustomAction(this, Translatrix.getTranslationString("FormatClear"), new HTML.UnknownTag(""));
+               actionInsertAnchor    = new CustomAction(this, Translatrix.getTranslationString("InsertAnchor") + menuDialog, HTML.Tag.A);
+
+               /* Build the menus */
+               /* FILE Menu */
+               jMenuFile              = new JMenu(Translatrix.getTranslationString("File"));
+               htMenus.put(KEY_MENU_FILE, jMenuFile);
+               JMenuItem jmiNew       = new JMenuItem(Translatrix.getTranslationString("NewDocument"));                     jmiNew.setActionCommand("newdoc");        jmiNew.addActionListener(this);      jmiNew.setAccelerator(KeyStroke.getKeyStroke('N', java.awt.Event.CTRL_MASK, false));      if(showMenuIcons) { jmiNew.setIcon(getEkitIcon("New")); }; jMenuFile.add(jmiNew);
+               JMenuItem jmiOpenHTML  = new JMenuItem(Translatrix.getTranslationString("OpenDocument") + menuDialog);       jmiOpenHTML.setActionCommand("openhtml"); jmiOpenHTML.addActionListener(this); jmiOpenHTML.setAccelerator(KeyStroke.getKeyStroke('O', java.awt.Event.CTRL_MASK, false)); if(showMenuIcons) { jmiOpenHTML.setIcon(getEkitIcon("Open")); }; jMenuFile.add(jmiOpenHTML);
+               JMenuItem jmiOpenCSS   = new JMenuItem(Translatrix.getTranslationString("OpenStyle") + menuDialog);          jmiOpenCSS.setActionCommand("opencss");   jmiOpenCSS.addActionListener(this);  jMenuFile.add(jmiOpenCSS);
+               JMenuItem jmiOpenB64   = new JMenuItem(Translatrix.getTranslationString("OpenBase64Document") + menuDialog); jmiOpenB64.setActionCommand("openb64");   jmiOpenB64.addActionListener(this);  jMenuFile.add(jmiOpenB64);
+               jMenuFile.addSeparator();
+               JMenuItem jmiSave      = new JMenuItem(Translatrix.getTranslationString("Save"));                  jmiSave.setActionCommand("save");         jmiSave.addActionListener(this);     jmiSave.setAccelerator(KeyStroke.getKeyStroke('S', java.awt.Event.CTRL_MASK, false)); if(showMenuIcons) { jmiSave.setIcon(getEkitIcon("Save")); }; jMenuFile.add(jmiSave);
+               JMenuItem jmiSaveAs    = new JMenuItem(Translatrix.getTranslationString("SaveAs") + menuDialog);   jmiSaveAs.setActionCommand("saveas");     jmiSaveAs.addActionListener(this);   jMenuFile.add(jmiSaveAs);
+               JMenuItem jmiSaveBody  = new JMenuItem(Translatrix.getTranslationString("SaveBody") + menuDialog); jmiSaveBody.setActionCommand("savebody"); jmiSaveBody.addActionListener(this); jMenuFile.add(jmiSaveBody);
+               JMenuItem jmiSaveRTF   = new JMenuItem(Translatrix.getTranslationString("SaveRTF") + menuDialog);  jmiSaveRTF.setActionCommand("savertf");   jmiSaveRTF.addActionListener(this);  jMenuFile.add(jmiSaveRTF);
+               JMenuItem jmiSaveB64   = new JMenuItem(Translatrix.getTranslationString("SaveB64") + menuDialog);  jmiSaveB64.setActionCommand("saveb64");   jmiSaveB64.addActionListener(this);  jMenuFile.add(jmiSaveB64);
+               jMenuFile.addSeparator();
+               JMenuItem jmiSerialOut = new JMenuItem(Translatrix.getTranslationString("Serialize") + menuDialog);   jmiSerialOut.setActionCommand("serialize");  jmiSerialOut.addActionListener(this); jMenuFile.add(jmiSerialOut);
+               JMenuItem jmiSerialIn  = new JMenuItem(Translatrix.getTranslationString("ReadFromSer") + menuDialog); jmiSerialIn.setActionCommand("readfromser"); jmiSerialIn.addActionListener(this);  jMenuFile.add(jmiSerialIn);
+               jMenuFile.addSeparator();
+               JMenuItem jmiExit      = new JMenuItem(Translatrix.getTranslationString("Exit")); jmiExit.setActionCommand("exit"); jmiExit.addActionListener(this); jMenuFile.add(jmiExit);
+
+               /* EDIT Menu */
+               jMenuEdit            = new JMenu(Translatrix.getTranslationString("Edit"));
+               htMenus.put(KEY_MENU_EDIT, jMenuEdit);
+               if(sysClipboard != null)
+               {
+                       // System Clipboard versions of menu commands
+                       JMenuItem jmiCut     = new JMenuItem(Translatrix.getTranslationString("Cut"));   jmiCut.setActionCommand("textcut");     jmiCut.addActionListener(this);   jmiCut.setAccelerator(KeyStroke.getKeyStroke('X', java.awt.Event.CTRL_MASK, false));   if(showMenuIcons) { jmiCut.setIcon(getEkitIcon("Cut")); }     jMenuEdit.add(jmiCut);
+                       JMenuItem jmiCopy    = new JMenuItem(Translatrix.getTranslationString("Copy"));  jmiCopy.setActionCommand("textcopy");   jmiCopy.addActionListener(this);  jmiCopy.setAccelerator(KeyStroke.getKeyStroke('C', java.awt.Event.CTRL_MASK, false));  if(showMenuIcons) { jmiCopy.setIcon(getEkitIcon("Copy")); }   jMenuEdit.add(jmiCopy);
+                       JMenuItem jmiPaste   = new JMenuItem(Translatrix.getTranslationString("Paste")); jmiPaste.setActionCommand("textpaste"); jmiPaste.addActionListener(this); jmiPaste.setAccelerator(KeyStroke.getKeyStroke('V', java.awt.Event.CTRL_MASK, false)); if(showMenuIcons) { jmiPaste.setIcon(getEkitIcon("Paste")); } jMenuEdit.add(jmiPaste);
+               }
+               else
+               {
+                       // DefaultEditorKit versions of menu commands
+                       JMenuItem jmiCut     = new JMenuItem(new DefaultEditorKit.CutAction());   jmiCut.setText(Translatrix.getTranslationString("Cut"));     jmiCut.setAccelerator(KeyStroke.getKeyStroke('X', java.awt.Event.CTRL_MASK, false));   if(showMenuIcons) { jmiCut.setIcon(getEkitIcon("Cut")); }     jMenuEdit.add(jmiCut);
+                       JMenuItem jmiCopy    = new JMenuItem(new DefaultEditorKit.CopyAction());  jmiCopy.setText(Translatrix.getTranslationString("Copy"));   jmiCopy.setAccelerator(KeyStroke.getKeyStroke('C', java.awt.Event.CTRL_MASK, false));  if(showMenuIcons) { jmiCopy.setIcon(getEkitIcon("Copy")); }   jMenuEdit.add(jmiCopy);
+                       JMenuItem jmiPaste   = new JMenuItem(new DefaultEditorKit.PasteAction()); jmiPaste.setText(Translatrix.getTranslationString("Paste")); jmiPaste.setAccelerator(KeyStroke.getKeyStroke('V', java.awt.Event.CTRL_MASK, false)); if(showMenuIcons) { jmiPaste.setIcon(getEkitIcon("Paste")); } jMenuEdit.add(jmiPaste);
+               }
+               jMenuEdit.addSeparator();
+               JMenuItem jmiUndo    = new JMenuItem(undoAction); jmiUndo.setAccelerator(KeyStroke.getKeyStroke('Z', java.awt.Event.CTRL_MASK, false)); jMenuEdit.add(jmiUndo);
+               JMenuItem jmiRedo    = new JMenuItem(redoAction); jmiRedo.setAccelerator(KeyStroke.getKeyStroke('Y', java.awt.Event.CTRL_MASK, false)); jMenuEdit.add(jmiRedo);
+               jMenuEdit.addSeparator();
+               JMenuItem jmiSelAll  = new JMenuItem((Action)actions.get(DefaultEditorKit.selectAllAction));       jmiSelAll.setText(Translatrix.getTranslationString("SelectAll"));        jmiSelAll.setAccelerator(KeyStroke.getKeyStroke('A', java.awt.Event.CTRL_MASK, false)); jMenuEdit.add(jmiSelAll);
+               JMenuItem jmiSelPara = new JMenuItem((Action)actions.get(DefaultEditorKit.selectParagraphAction)); jmiSelPara.setText(Translatrix.getTranslationString("SelectParagraph")); jMenuEdit.add(jmiSelPara);
+               JMenuItem jmiSelLine = new JMenuItem((Action)actions.get(DefaultEditorKit.selectLineAction));      jmiSelLine.setText(Translatrix.getTranslationString("SelectLine"));      jMenuEdit.add(jmiSelLine);
+               JMenuItem jmiSelWord = new JMenuItem((Action)actions.get(DefaultEditorKit.selectWordAction));      jmiSelWord.setText(Translatrix.getTranslationString("SelectWord"));      jMenuEdit.add(jmiSelWord);
+
+               /* VIEW Menu */
+               jMenuView        = new JMenu(Translatrix.getTranslationString("View"));
+               htMenus.put(KEY_MENU_VIEW, jMenuView);
+               jcbmiViewToolbar = new JCheckBoxMenuItem(Translatrix.getTranslationString("ViewToolbar"), false); jcbmiViewToolbar.setActionCommand("toggletoolbar"); jcbmiViewToolbar.addActionListener(this); jMenuView.add(jcbmiViewToolbar);
+               jcbmiViewSource  = new JCheckBoxMenuItem(Translatrix.getTranslationString("ViewSource"), false);  jcbmiViewSource.setActionCommand("viewsource");     jcbmiViewSource.addActionListener(this);  jMenuView.add(jcbmiViewSource);
+
+               /* FONT Menu */
+               jMenuFont              = new JMenu(Translatrix.getTranslationString("Font"));
+               htMenus.put(KEY_MENU_FONT, jMenuFont);
+               JMenuItem jmiBold      = new JMenuItem(actionFontBold);      jmiBold.setText(Translatrix.getTranslationString("FontBold"));           jmiBold.setAccelerator(KeyStroke.getKeyStroke('B', java.awt.Event.CTRL_MASK, false));      if(showMenuIcons) { jmiBold.setIcon(getEkitIcon("Bold")); }           jMenuFont.add(jmiBold);
+               JMenuItem jmiItalic    = new JMenuItem(actionFontItalic);    jmiItalic.setText(Translatrix.getTranslationString("FontItalic"));       jmiItalic.setAccelerator(KeyStroke.getKeyStroke('I', java.awt.Event.CTRL_MASK, false));    if(showMenuIcons) { jmiItalic.setIcon(getEkitIcon("Italic")); }       jMenuFont.add(jmiItalic);
+               JMenuItem jmiUnderline = new JMenuItem(actionFontUnderline); jmiUnderline.setText(Translatrix.getTranslationString("FontUnderline")); jmiUnderline.setAccelerator(KeyStroke.getKeyStroke('U', java.awt.Event.CTRL_MASK, false)); if(showMenuIcons) { jmiUnderline.setIcon(getEkitIcon("Underline")); } jMenuFont.add(jmiUnderline);
+               JMenuItem jmiStrike    = new JMenuItem(actionFontStrike);    jmiStrike.setText(Translatrix.getTranslationString("FontStrike"));                                                                                                  if(showMenuIcons) { jmiStrike.setIcon(getEkitIcon("Strike")); }       jMenuFont.add(jmiStrike);
+               jMenuFont.addSeparator();
+               jMenuFont.add(new JMenuItem(new FormatAction(this, Translatrix.getTranslationString("FormatBig"), HTML.Tag.BIG)));
+               jMenuFont.add(new JMenuItem(new FormatAction(this, Translatrix.getTranslationString("FormatSmall"), HTML.Tag.SMALL)));
+               JMenu jMenuFontSize = new JMenu(Translatrix.getTranslationString("FontSize"));
+                       String fontSizeKey = "size";
+                       customAttr = new Hashtable(); customAttr.put(fontSizeKey,"1");
+                       jMenuFontSize.add(new JMenuItem(new CustomAction(this, Translatrix.getTranslationString("FontSize1"), HTML.Tag.FONT, customAttr)));
+                       customAttr = new Hashtable(); customAttr.put(fontSizeKey,"2");
+                       jMenuFontSize.add(new JMenuItem(new CustomAction(this, Translatrix.getTranslationString("FontSize2"), HTML.Tag.FONT, customAttr)));
+                       customAttr = new Hashtable(); customAttr.put(fontSizeKey,"3");
+                       jMenuFontSize.add(new JMenuItem(new CustomAction(this, Translatrix.getTranslationString("FontSize3"), HTML.Tag.FONT, customAttr)));
+                       customAttr = new Hashtable(); customAttr.put(fontSizeKey,"4");
+                       jMenuFontSize.add(new JMenuItem(new CustomAction(this, Translatrix.getTranslationString("FontSize4"), HTML.Tag.FONT, customAttr)));
+                       customAttr = new Hashtable(); customAttr.put(fontSizeKey,"5");
+                       jMenuFontSize.add(new JMenuItem(new CustomAction(this, Translatrix.getTranslationString("FontSize5"), HTML.Tag.FONT, customAttr)));
+                       customAttr = new Hashtable(); customAttr.put(fontSizeKey,"6");
+                       jMenuFontSize.add(new JMenuItem(new CustomAction(this, Translatrix.getTranslationString("FontSize6"), HTML.Tag.FONT, customAttr)));
+                       customAttr = new Hashtable(); customAttr.put(fontSizeKey,"7");
+                       jMenuFontSize.add(new JMenuItem(new CustomAction(this, Translatrix.getTranslationString("FontSize7"), HTML.Tag.FONT, customAttr)));
+               jMenuFont.add(jMenuFontSize);
+               jMenuFont.addSeparator();
+               JMenuItem jmiSupscript = new JMenuItem(actionFontSuperscript); if(showMenuIcons) { jmiSupscript.setIcon(getEkitIcon("Super")); } jMenuFont.add(jmiSupscript);
+               JMenuItem jmiSubscript = new JMenuItem(actionFontSubscript);   if(showMenuIcons) { jmiSubscript.setIcon(getEkitIcon("Sub")); }   jMenuFont.add(jmiSubscript);
+               jMenuFont.addSeparator();
+               JMenuItem jmiSerif      = new JMenuItem((Action)actions.get("font-family-Serif"));      jmiSerif.setText(Translatrix.getTranslationString("FontSerif"));           jMenuFont.add(jmiSerif);
+               JMenuItem jmiSansSerif  = new JMenuItem((Action)actions.get("font-family-SansSerif"));  jmiSansSerif.setText(Translatrix.getTranslationString("FontSansserif"));   jMenuFont.add(jmiSansSerif);
+               JMenuItem jmiMonospaced = new JMenuItem((Action)actions.get("font-family-Monospaced")); jmiMonospaced.setText(Translatrix.getTranslationString("FontMonospaced")); jMenuFont.add(jmiMonospaced);
+               JMenuItem jmiSelectFont = new JMenuItem(actionSelectFont);                                                                                                         jMenuFont.add(jmiSelectFont);
+               jMenuFont.addSeparator();
+               JMenu jMenuFontColor = new JMenu(Translatrix.getTranslationString("Color"));
+                       customAttr = new Hashtable(); customAttr.put("color","black");
+                       jMenuFontColor.add(new JMenuItem(new CustomAction(this, Translatrix.getTranslationString("CustomColor") + menuDialog, HTML.Tag.FONT, customAttr)));
+                       jMenuFontColor.add(new JMenuItem(new StyledEditorKit.ForegroundAction(Translatrix.getTranslationString("ColorAqua"),    new Color(  0,255,255))));
+                       jMenuFontColor.add(new JMenuItem(new StyledEditorKit.ForegroundAction(Translatrix.getTranslationString("ColorBlack"),   new Color(  0,  0,  0))));
+                       jMenuFontColor.add(new JMenuItem(new StyledEditorKit.ForegroundAction(Translatrix.getTranslationString("ColorBlue"),    new Color(  0,  0,255))));
+                       jMenuFontColor.add(new JMenuItem(new StyledEditorKit.ForegroundAction(Translatrix.getTranslationString("ColorFuschia"), new Color(255,  0,255))));
+                       jMenuFontColor.add(new JMenuItem(new StyledEditorKit.ForegroundAction(Translatrix.getTranslationString("ColorGray"),    new Color(128,128,128))));
+                       jMenuFontColor.add(new JMenuItem(new StyledEditorKit.ForegroundAction(Translatrix.getTranslationString("ColorGreen"),   new Color(  0,128,  0))));
+                       jMenuFontColor.add(new JMenuItem(new StyledEditorKit.ForegroundAction(Translatrix.getTranslationString("ColorLime"),    new Color(  0,255,  0))));
+                       jMenuFontColor.add(new JMenuItem(new StyledEditorKit.ForegroundAction(Translatrix.getTranslationString("ColorMaroon"),  new Color(128,  0,  0))));
+                       jMenuFontColor.add(new JMenuItem(new StyledEditorKit.ForegroundAction(Translatrix.getTranslationString("ColorNavy"),    new Color(  0,  0,128))));
+                       jMenuFontColor.add(new JMenuItem(new StyledEditorKit.ForegroundAction(Translatrix.getTranslationString("ColorOlive"),   new Color(128,128,  0))));
+                       jMenuFontColor.add(new JMenuItem(new StyledEditorKit.ForegroundAction(Translatrix.getTranslationString("ColorPurple"),  new Color(128,  0,128))));
+                       jMenuFontColor.add(new JMenuItem(new StyledEditorKit.ForegroundAction(Translatrix.getTranslationString("ColorRed"),     new Color(255,  0,  0))));
+                       jMenuFontColor.add(new JMenuItem(new StyledEditorKit.ForegroundAction(Translatrix.getTranslationString("ColorSilver"),  new Color(192,192,192))));
+                       jMenuFontColor.add(new JMenuItem(new StyledEditorKit.ForegroundAction(Translatrix.getTranslationString("ColorTeal"),    new Color(  0,128,128))));
+                       jMenuFontColor.add(new JMenuItem(new StyledEditorKit.ForegroundAction(Translatrix.getTranslationString("ColorWhite"),   new Color(255,255,255))));
+                       jMenuFontColor.add(new JMenuItem(new StyledEditorKit.ForegroundAction(Translatrix.getTranslationString("ColorYellow"),  new Color(255,255,  0))));
+               jMenuFont.add(jMenuFontColor);
+
+               /* FORMAT Menu */
+               jMenuFormat            = new JMenu(Translatrix.getTranslationString("Format"));
+               htMenus.put(KEY_MENU_FORMAT, jMenuFormat);
+               JMenu jMenuFormatAlign = new JMenu(Translatrix.getTranslationString("Align"));
+                       jMenuFormatAlign.add(new JMenuItem(new StyledEditorKit.AlignmentAction(Translatrix.getTranslationString("AlignLeft"), StyleConstants.ALIGN_LEFT)));
+                       jMenuFormatAlign.add(new JMenuItem(new StyledEditorKit.AlignmentAction(Translatrix.getTranslationString("AlignCenter"), StyleConstants.ALIGN_CENTER)));
+                       jMenuFormatAlign.add(new JMenuItem(new StyledEditorKit.AlignmentAction(Translatrix.getTranslationString("AlignRight"), StyleConstants.ALIGN_RIGHT)));
+                       jMenuFormatAlign.add(new JMenuItem(new StyledEditorKit.AlignmentAction(Translatrix.getTranslationString("AlignJustified"), StyleConstants.ALIGN_JUSTIFIED)));
+               jMenuFormat.add(jMenuFormatAlign);
+               jMenuFormat.addSeparator();
+               JMenu jMenuFormatHeading = new JMenu(Translatrix.getTranslationString("Heading"));
+                       jMenuFormatHeading.add(new JMenuItem(new FormatAction(this, Translatrix.getTranslationString("Heading1"), HTML.Tag.H1)));
+                       jMenuFormatHeading.add(new JMenuItem(new FormatAction(this, Translatrix.getTranslationString("Heading2"), HTML.Tag.H2)));
+                       jMenuFormatHeading.add(new JMenuItem(new FormatAction(this, Translatrix.getTranslationString("Heading3"), HTML.Tag.H3)));
+                       jMenuFormatHeading.add(new JMenuItem(new FormatAction(this, Translatrix.getTranslationString("Heading4"), HTML.Tag.H4)));
+                       jMenuFormatHeading.add(new JMenuItem(new FormatAction(this, Translatrix.getTranslationString("Heading5"), HTML.Tag.H5)));
+                       jMenuFormatHeading.add(new JMenuItem(new FormatAction(this, Translatrix.getTranslationString("Heading6"), HTML.Tag.H6)));
+               jMenuFormat.add(jMenuFormatHeading);
+               jMenuFormat.addSeparator();
+               JMenuItem jmiUList = new JMenuItem(actionListUnordered); if(showMenuIcons) { jmiUList.setIcon(getEkitIcon("UList")); } jMenuFormat.add(jmiUList);
+               JMenuItem jmiOList = new JMenuItem(actionListOrdered);   if(showMenuIcons) { jmiOList.setIcon(getEkitIcon("OList")); } jMenuFormat.add(jmiOList);
+               jMenuFormat.add(new JMenuItem(new FormatAction(this, Translatrix.getTranslationString("ListItem"), HTML.Tag.LI)));
+               jMenuFormat.addSeparator();
+               jMenuFormat.add(new JMenuItem(new FormatAction(this, Translatrix.getTranslationString("FormatBlockquote"), HTML.Tag.BLOCKQUOTE)));
+               jMenuFormat.add(new JMenuItem(new FormatAction(this, Translatrix.getTranslationString("FormatPre"), HTML.Tag.PRE)));
+               jMenuFormat.add(new JMenuItem(new FormatAction(this, Translatrix.getTranslationString("FormatStrong"), HTML.Tag.STRONG)));
+               jMenuFormat.add(new JMenuItem(new FormatAction(this, Translatrix.getTranslationString("FormatEmphasis"), HTML.Tag.EM)));
+               jMenuFormat.add(new JMenuItem(new FormatAction(this, Translatrix.getTranslationString("FormatTT"), HTML.Tag.TT)));
+               jMenuFormat.add(new JMenuItem(new FormatAction(this, Translatrix.getTranslationString("FormatSpan"), HTML.Tag.SPAN)));
+               jMenuFormat.addSeparator();
+               JMenuItem jmiClearStyles = new JMenuItem(actionClearFormat); if(showMenuIcons) { jmiClearStyles.setIcon(getEkitIcon("ClearFormat")); }; jMenuFormat.add(jmiClearStyles);
+
+               /* INSERT Menu */
+               jMenuInsert              = new JMenu(Translatrix.getTranslationString("Insert"));
+               htMenus.put(KEY_MENU_INSERT, jMenuInsert);
+               jMenuInsert.add(new JMenuItem(actionInsertAnchor));
+               JMenuItem jmiBreak       = new JMenuItem(Translatrix.getTranslationString("InsertBreak"));                    jmiBreak.setActionCommand("insertbreak"); jmiBreak.addActionListener(this); jmiBreak.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, java.awt.Event.SHIFT_MASK, false)); jMenuInsert.add(jmiBreak);
+               JMenuItem jmiNBSP        = new JMenuItem(Translatrix.getTranslationString("InsertNBSP"));                     jmiNBSP.setActionCommand("insertnbsp");   jmiNBSP.addActionListener(this);  jMenuInsert.add(jmiNBSP);
+               JMenuItem jmiHRule       = new JMenuItem((Action)actions.get("InsertHR"));                                    jmiHRule.setText(Translatrix.getTranslationString("InsertHorizontalRule")); jMenuInsert.add(jmiHRule);
+               jMenuInsert.addSeparator();
+               JMenuItem jmiImageLocal  = new JMenuItem(Translatrix.getTranslationString("InsertLocalImage") + menuDialog);  jmiImageLocal.setActionCommand("insertlocalimage"); jmiImageLocal.addActionListener(this); jMenuInsert.add(jmiImageLocal);
+               JMenuItem jmiImageServer = new JMenuItem(Translatrix.getTranslationString("InsertServerImage") + menuDialog); jmiImageServer.setActionCommand("insertserverimage"); jmiImageServer.addActionListener(this); jMenuInsert.add(jmiImageServer);
+
+               /* TABLE Menu */
+               jMenuTable              = new JMenu(Translatrix.getTranslationString("Table"));
+               htMenus.put(KEY_MENU_TABLE, jMenuTable);
+               JMenuItem jmiTable       = new JMenuItem(Translatrix.getTranslationString("InsertTable") + menuDialog); jmiTable.setActionCommand("inserttable");             jmiTable.addActionListener(this);       jMenuTable.add(jmiTable);
+               jMenuTable.addSeparator();
+               JMenuItem jmiTableRow    = new JMenuItem(Translatrix.getTranslationString("InsertTableRow"));           jmiTableRow.setActionCommand("inserttablerow");       jmiTableRow.addActionListener(this);    jMenuTable.add(jmiTableRow);
+               JMenuItem jmiTableCol    = new JMenuItem(Translatrix.getTranslationString("InsertTableColumn"));        jmiTableCol.setActionCommand("inserttablecolumn");    jmiTableCol.addActionListener(this);    jMenuTable.add(jmiTableCol);
+               jMenuTable.addSeparator();
+               JMenuItem jmiTableRowDel = new JMenuItem(Translatrix.getTranslationString("DeleteTableRow"));           jmiTableRowDel.setActionCommand("deletetablerow");    jmiTableRowDel.addActionListener(this); jMenuTable.add(jmiTableRowDel);
+               JMenuItem jmiTableColDel = new JMenuItem(Translatrix.getTranslationString("DeleteTableColumn"));        jmiTableColDel.setActionCommand("deletetablecolumn"); jmiTableColDel.addActionListener(this); jMenuTable.add(jmiTableColDel);
+
+               /* FORMS Menu */
+               jMenuForms                    = new JMenu(Translatrix.getTranslationString("Forms"));
+               htMenus.put(KEY_MENU_FORMS, jMenuForms);
+               JMenuItem jmiFormInsertForm   = new JMenuItem(Translatrix.getTranslationString("FormInsertForm")); jmiFormInsertForm.setActionCommand("insertform");     jmiFormInsertForm.addActionListener(this); jMenuForms.add(jmiFormInsertForm);
+               jMenuForms.addSeparator();
+               JMenuItem jmiFormTextfield    = new JMenuItem(Translatrix.getTranslationString("FormTextfield"));  jmiFormTextfield.setActionCommand("inserttextfield"); jmiFormTextfield.addActionListener(this);  jMenuForms.add(jmiFormTextfield);
+               JMenuItem jmiFormTextarea     = new JMenuItem(Translatrix.getTranslationString("FormTextarea"));   jmiFormTextarea.setActionCommand("inserttextarea");   jmiFormTextarea.addActionListener(this);   jMenuForms.add(jmiFormTextarea);
+               JMenuItem jmiFormCheckbox     = new JMenuItem(Translatrix.getTranslationString("FormCheckbox"));   jmiFormCheckbox.setActionCommand("insertcheckbox");   jmiFormCheckbox.addActionListener(this);   jMenuForms.add(jmiFormCheckbox);
+               JMenuItem jmiFormRadio        = new JMenuItem(Translatrix.getTranslationString("FormRadio"));      jmiFormRadio.setActionCommand("insertradiobutton");   jmiFormRadio.addActionListener(this);      jMenuForms.add(jmiFormRadio);
+               JMenuItem jmiFormPassword     = new JMenuItem(Translatrix.getTranslationString("FormPassword"));   jmiFormPassword.setActionCommand("insertpassword");   jmiFormPassword.addActionListener(this);   jMenuForms.add(jmiFormPassword);
+               jMenuForms.addSeparator();
+               JMenuItem jmiFormButton       = new JMenuItem(Translatrix.getTranslationString("FormButton"));       jmiFormButton.setActionCommand("insertbutton");             jmiFormButton.addActionListener(this);       jMenuForms.add(jmiFormButton);
+               JMenuItem jmiFormButtonSubmit = new JMenuItem(Translatrix.getTranslationString("FormButtonSubmit")); jmiFormButtonSubmit.setActionCommand("insertbuttonsubmit"); jmiFormButtonSubmit.addActionListener(this); jMenuForms.add(jmiFormButtonSubmit);
+               JMenuItem jmiFormButtonReset  = new JMenuItem(Translatrix.getTranslationString("FormButtonReset"));  jmiFormButtonReset.setActionCommand("insertbuttonreset");   jmiFormButtonReset.addActionListener(this);  jMenuForms.add(jmiFormButtonReset);
+
+               /* SEARCH Menu */
+               jMenuSearch            = new JMenu(Translatrix.getTranslationString("Search"));
+               htMenus.put(KEY_MENU_SEARCH, jMenuSearch);
+               JMenuItem jmiFind      = new JMenuItem(Translatrix.getTranslationString("SearchFind"));      jmiFind.setActionCommand("find");           jmiFind.addActionListener(this);      jmiFind.setAccelerator(KeyStroke.getKeyStroke('F', java.awt.Event.CTRL_MASK, false));      jMenuSearch.add(jmiFind);
+               JMenuItem jmiFindAgain = new JMenuItem(Translatrix.getTranslationString("SearchFindAgain")); jmiFindAgain.setActionCommand("findagain"); jmiFindAgain.addActionListener(this); jmiFindAgain.setAccelerator(KeyStroke.getKeyStroke('G', java.awt.Event.CTRL_MASK, false)); jMenuSearch.add(jmiFindAgain);
+               JMenuItem jmiReplace   = new JMenuItem(Translatrix.getTranslationString("SearchReplace"));   jmiReplace.setActionCommand("replace");     jmiReplace.addActionListener(this);   jmiReplace.setAccelerator(KeyStroke.getKeyStroke('R', java.awt.Event.CTRL_MASK, false));   jMenuSearch.add(jmiReplace);
+
+               /* HELP Menu */
+               jMenuHelp = new JMenu(Translatrix.getTranslationString("Help"));
+               htMenus.put(KEY_MENU_HELP, jMenuHelp);
+               JMenuItem jmiAbout = new JMenuItem(Translatrix.getTranslationString("About")); jmiAbout.setActionCommand("helpabout"); jmiAbout.addActionListener(this); jMenuHelp.add(jmiAbout);
+
+               /* DEBUG Menu */
+               jMenuDebug           = new JMenu(Translatrix.getTranslationString("Debug"));
+               htMenus.put(KEY_MENU_DEBUG, jMenuDebug);
+               JMenuItem jmiDesc    = new JMenuItem(Translatrix.getTranslationString("DescribeDoc")); jmiDesc.setActionCommand("describe");       jmiDesc.addActionListener(this);    jMenuDebug.add(jmiDesc);
+               JMenuItem jmiDescCSS = new JMenuItem(Translatrix.getTranslationString("DescribeCSS")); jmiDescCSS.setActionCommand("describecss"); jmiDescCSS.addActionListener(this); jMenuDebug.add(jmiDescCSS);
+               JMenuItem jmiTag     = new JMenuItem(Translatrix.getTranslationString("WhatTags"));    jmiTag.setActionCommand("whattags");        jmiTag.addActionListener(this);     jMenuDebug.add(jmiTag);
+
+               /* Create menubar and add menus */
+               jMenuBar = new JMenuBar();
+               jMenuBar.add(jMenuFile);
+               jMenuBar.add(jMenuEdit);
+               jMenuBar.add(jMenuView);
+               jMenuBar.add(jMenuFont);
+               jMenuBar.add(jMenuFormat);
+               jMenuBar.add(jMenuSearch);
+               jMenuBar.add(jMenuInsert);
+               jMenuBar.add(jMenuTable);
+               jMenuBar.add(jMenuForms);
+               jMenuBar.add(jMenuHelp);
+               if(debugMode)
+               {
+                       jMenuBar.add(jMenuDebug);
+               }
+
+               /* Create the toolbar */
+               jToolBar = new JToolBar(JToolBar.HORIZONTAL);
+               jToolBar.setFloatable(false);
+               jbtnNewHTML     = new JButtonNoFocus(getEkitIcon("New"));  jbtnNewHTML.setToolTipText(Translatrix.getTranslationString("NewDocument"));   jbtnNewHTML.setActionCommand("newdoc");    jbtnNewHTML.addActionListener(this);  jToolBar.add(jbtnNewHTML);  htTools.put(KEY_TOOL_NEW, jbtnNewHTML);
+               jbtnOpenHTML    = new JButtonNoFocus(getEkitIcon("Open")); jbtnOpenHTML.setToolTipText(Translatrix.getTranslationString("OpenDocument")); jbtnOpenHTML.setActionCommand("openhtml"); jbtnOpenHTML.addActionListener(this); jToolBar.add(jbtnOpenHTML); htTools.put(KEY_TOOL_OPEN, jbtnOpenHTML);
+               jbtnSaveHTML    = new JButtonNoFocus(getEkitIcon("Save")); jbtnSaveHTML.setToolTipText(Translatrix.getTranslationString("SaveDocument")); jbtnSaveHTML.setActionCommand("saveas");   jbtnSaveHTML.addActionListener(this); jToolBar.add(jbtnSaveHTML); htTools.put(KEY_TOOL_SAVE, jbtnSaveHTML);
+               jToolBar.add(new JToolBar.Separator());
+               jbtnCut         = new JButtonNoFocus(new DefaultEditorKit.CutAction());   jbtnCut.setIcon(getEkitIcon("Cut"));     jbtnCut.setText(null);   jbtnCut.setToolTipText(Translatrix.getTranslationString("Cut"));     jToolBar.add(jbtnCut);   htTools.put(KEY_TOOL_CUT, jbtnCut);
+               jbtnCopy        = new JButtonNoFocus(new DefaultEditorKit.CopyAction());  jbtnCopy.setIcon(getEkitIcon("Copy"));   jbtnCopy.setText(null);  jbtnCopy.setToolTipText(Translatrix.getTranslationString("Copy"));   jToolBar.add(jbtnCopy);  htTools.put(KEY_TOOL_COPY, jbtnCopy);
+               jbtnPaste       = new JButtonNoFocus(new DefaultEditorKit.PasteAction()); jbtnPaste.setIcon(getEkitIcon("Paste")); jbtnPaste.setText(null); jbtnPaste.setToolTipText(Translatrix.getTranslationString("Paste")); jToolBar.add(jbtnPaste); htTools.put(KEY_TOOL_PASTE, jbtnPaste);
+               jToolBar.add(new JToolBar.Separator());
+               jbtnBold        = new JButtonNoFocus(actionFontBold);        jbtnBold.setIcon(getEkitIcon("Bold"));               jbtnBold.setText(null);        jbtnBold.setToolTipText(Translatrix.getTranslationString("FontBold"));                 jToolBar.add(jbtnBold);        htTools.put(KEY_TOOL_BOLD, jbtnBold);
+               jbtnItalic      = new JButtonNoFocus(actionFontItalic);      jbtnItalic.setIcon(getEkitIcon("Italic"));           jbtnItalic.setText(null);      jbtnItalic.setToolTipText(Translatrix.getTranslationString("FontItalic"));             jToolBar.add(jbtnItalic);      htTools.put(KEY_TOOL_ITALIC, jbtnItalic);
+               jbtnUnderline   = new JButtonNoFocus(actionFontUnderline);   jbtnUnderline.setIcon(getEkitIcon("Underline"));     jbtnUnderline.setText(null);   jbtnUnderline.setToolTipText(Translatrix.getTranslationString("FontUnderline"));       jToolBar.add(jbtnUnderline);   htTools.put(KEY_TOOL_UNDERLINE, jbtnUnderline);
+               jbtnStrike      = new JButtonNoFocus(actionFontStrike);      jbtnStrike.setIcon(getEkitIcon("Strike"));           jbtnStrike.setText(null);      jbtnStrike.setToolTipText(Translatrix.getTranslationString("FontStrike"));             jToolBar.add(jbtnStrike);      htTools.put(KEY_TOOL_STRIKE, jbtnStrike);
+               jbtnSuperscript = new JButtonNoFocus(actionFontSuperscript); jbtnSuperscript.setIcon(getEkitIcon("Super"));       jbtnSuperscript.setText(null); jbtnSuperscript.setToolTipText(Translatrix.getTranslationString("FontSuperscript")); jToolBar.add(jbtnSuperscript);   htTools.put(KEY_TOOL_SUPER, jbtnSuperscript);
+               jbtnSubscript   = new JButtonNoFocus(actionFontSubscript);   jbtnSubscript.setIcon(getEkitIcon("Sub"));           jbtnSubscript.setText(null);   jbtnSubscript.setToolTipText(Translatrix.getTranslationString("FontSubscript"));     jToolBar.add(jbtnSubscript);     htTools.put(KEY_TOOL_SUB, jbtnSubscript);
+               jbtnUList       = new JButtonNoFocus(actionListUnordered);   jbtnUList.setIcon(getEkitIcon("UList"));             jbtnUList.setText(null);       jbtnUList.setToolTipText(Translatrix.getTranslationString("ListUnordered"));           jToolBar.add(jbtnUList);       htTools.put(KEY_TOOL_ULIST, jbtnUList);
+               jbtnOList       = new JButtonNoFocus(actionListOrdered);     jbtnOList.setIcon(getEkitIcon("OList"));             jbtnOList.setText(null);       jbtnOList.setToolTipText(Translatrix.getTranslationString("ListOrdered"));             jToolBar.add(jbtnOList);       htTools.put(KEY_TOOL_OLIST, jbtnOList);
+               jbtnClearFormat = new JButtonNoFocus(actionClearFormat);     jbtnClearFormat.setIcon(getEkitIcon("ClearFormat")); jbtnClearFormat.setText(null); jbtnClearFormat.setToolTipText(Translatrix.getTranslationString("FormatClear"));       jToolBar.add(jbtnClearFormat); htTools.put(KEY_TOOL_CLEAR, jbtnClearFormat);
+               jToolBar.add(new JToolBar.Separator());
+               jbtnAnchor      = new JButtonNoFocus(actionInsertAnchor); jbtnAnchor.setIcon(getEkitIcon("Anchor")); jbtnAnchor.setText(null); jbtnAnchor.setToolTipText(Translatrix.getTranslationString("ToolAnchor")); jToolBar.add(jbtnAnchor); htTools.put(KEY_TOOL_ANCHOR, jbtnAnchor);
+               jToolBar.add(new JToolBar.Separator());
+               jtbtnViewSource = new JToggleButtonNoFocus(getEkitIcon("Source")); jtbtnViewSource.setText(null); jtbtnViewSource.setToolTipText(Translatrix.getTranslationString("ViewSource")); jtbtnViewSource.setActionCommand("viewsource"); jtbtnViewSource.addActionListener(this); jtbtnViewSource.setPreferredSize(jbtnAnchor.getPreferredSize()); jtbtnViewSource.setMinimumSize(jbtnAnchor.getMinimumSize()); jtbtnViewSource.setMaximumSize(jbtnAnchor.getMaximumSize()); jToolBar.add(jtbtnViewSource); htTools.put(KEY_TOOL_SOURCE, jtbtnViewSource);
+               jToolBar.add(new JToolBar.Separator());
+               jcmbStyleSelector = new JComboBoxNoFocus(); jToolBar.add(jcmbStyleSelector); jcmbStyleSelector.setAction(new StylesAction(jcmbStyleSelector)); htTools.put(KEY_TOOL_STYLES, jcmbStyleSelector);
+
+               /* Create the scroll area for the text pane */
+               JScrollPane jspViewport = new JScrollPane(jtpMain);
+               jspViewport.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
+               jspViewport.setPreferredSize(new Dimension(400, 400));
+               jspViewport.setMinimumSize(new Dimension(32, 32));
+
+               /* Create the scroll area for the source viewer */
+               jspSource = new JScrollPane(jtpSource);
+               jspSource.setPreferredSize(new Dimension(400, 100));
+               jspSource.setMinimumSize(new Dimension(32, 32));
+
+               jspltDisplay = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
+               jspltDisplay.setTopComponent(jspViewport);
+               if(showViewSource)
+               {
+                       jspltDisplay.setBottomComponent(jspSource);
+               }
+               else
+               {
+                       jspltDisplay.setBottomComponent(null);
+               }
+
+               iSplitPos = jspltDisplay.getDividerLocation();
+
+               registerDocumentStyles();
+
+               /* Add the components to the app */
+               this.setLayout(new BorderLayout());
+               this.add(jspltDisplay, BorderLayout.CENTER);
+       }
+
+       /** Common Constructor
+         * @param sDocument         [String]  A text or HTML document to load in the editor upon startup.
+         * @param sStyleSheet       [String]  A CSS stylesheet to load in the editor upon startup.
+         * @param showViewSource    [boolean] Specifies whether or not to show the View Source window on startup.
+         * @param showMenuIcons     [boolean] Specifies whether or not to show icon pictures in menus.
+         * @param editModeExclusive [boolean] Specifies whether or not to use exclusive edit mode (recommended on).
+         * @param sLanguage         [String]  The language portion of the Internationalization Locale to run Ekit in.
+         * @param sCountry          [String]  The country portion of the Internationalization Locale to run Ekit in.
+         */
+       public EkitCore(String sDocument, String sStyleSheet, boolean showViewSource, boolean showMenuIcons, boolean editModeExclusive, String sLanguage, String sCountry, boolean base64)
+       {
+               this(sDocument, sStyleSheet, null, null, showViewSource, showMenuIcons, editModeExclusive, sLanguage, sCountry, base64, false);
+       }
+
+       /** Default Language Constructor
+         * @param sDocument         [String]  A text or HTML document to load in the editor upon startup.
+         * @param sStyleSheet       [String]  A CSS stylesheet to load in the editor upon startup.
+         * @param showViewSource    [boolean] Specifies whether or not to show the View Source window on startup.
+         * @param showMenuIcons     [boolean] Specifies whether or not to show icon pictures in menus.
+         * @param editModeExclusive [boolean] Specifies whether or not to use exclusive edit mode (recommended on).
+         */
+       public EkitCore(String sDocument, String sStyleSheet, boolean showViewSource, boolean showMenuIcons, boolean editModeExclusive, boolean base64)
+       {
+               this(sDocument, sStyleSheet, null, null, showViewSource, showMenuIcons, editModeExclusive, null, null, base64, false);
+       }
+
+       /** Raw/Base64 Document & Style Sheet URL Constructor (Ideal for EkitApplet)
+         * @param sRawDocument      [String]  A document encoded as a String to load in the editor upon startup.
+         * @param sRawDocument      [String]  A document encoded as a String to load in the editor upon startup.
+         * @param showViewSource    [boolean] Specifies whether or not to show the View Source window on startup.
+         * @param showMenuIcons     [boolean] Specifies whether or not to show icon pictures in menus.
+         * @param editModeExclusive [boolean] Specifies whether or not to use exclusive edit mode (recommended on).
+         * @param sLanguage         [String]  The language portion of the Internationalization Locale to run Ekit in.
+         * @param sCountry          [String]  The country portion of the Internationalization Locale to run Ekit in.
+         */
+       public EkitCore(String sRawDocument, URL urlStyleSheet, boolean showViewSource, boolean showMenuIcons, boolean editModeExclusive, String sLanguage, String sCountry, boolean base64)
+       {
+               this(null, null, sRawDocument, urlStyleSheet, showViewSource, showMenuIcons, editModeExclusive, sLanguage, sCountry, base64, false);
+       }
+
+       /** Document Constructor
+         * @param sRawDocument      [String]  A document encoded as a String to load in the editor upon startup.
+         * @param showViewSource    [boolean] Specifies whether or not to show the View Source window on startup.
+         * @param showMenuIcons     [boolean] Specifies whether or not to show icon pictures in menus.
+         * @param editModeExclusive [boolean] Specifies whether or not to use exclusive edit mode (recommended on).
+         * @param sLanguage         [String]  The language portion of the Internationalization Locale to run Ekit in.
+         * @param sCountry          [String]  The country portion of the Internationalization Locale to run Ekit in.
+         */
+       public EkitCore(String sRawDocument, boolean showViewSource, boolean showMenuIcons, boolean editModeExclusive, String sLanguage, String sCountry, boolean base64)
+       {
+               this(null, null, sRawDocument, null, showViewSource, showMenuIcons, editModeExclusive, sLanguage, sCountry, base64, false);
+       }
+
+       /** Default Language & Document Constructor
+         * @param sRawDocument      [String]  A document encoded as a String to load in the editor upon startup.
+         * @param showViewSource    [boolean] Specifies whether or not to show the View Source window on startup.
+         * @param showMenuIcons     [boolean] Specifies whether or not to show icon pictures in menus.
+         * @param editModeExclusive [boolean] Specifies whether or not to use exclusive edit mode (recommended on).
+         */
+       public EkitCore(String sRawDocument, boolean showViewSource, boolean showMenuIcons, boolean editModeExclusive, boolean base64)
+       {
+               this(null, null, sRawDocument, null, showViewSource, showMenuIcons, editModeExclusive, null, null, base64, false);
+       }
+
+       /** Flags & Language Constructor
+         * @param showViewSource    [boolean] Specifies whether or not to show the View Source window on startup.
+         * @param showMenuIcons     [boolean] Specifies whether or not to show icon pictures in menus.
+         * @param editModeExclusive [boolean] Specifies whether or not to use exclusive edit mode (recommended on).
+         * @param sLanguage         [String]  The language portion of the Internationalization Locale to run Ekit in.
+         * @param sCountry          [String]  The country portion of the Internationalization Locale to run Ekit in.
+         */
+       public EkitCore(boolean showViewSource, boolean showMenuIcons, boolean editModeExclusive, String sLanguage, String sCountry)
+       {
+               this(null, null, null, null, showViewSource, showMenuIcons, editModeExclusive, sLanguage, sCountry, false, false);
+       }
+
+       /** Flags Constructor
+         * @param showViewSource    [boolean] Specifies whether or not to show the View Source window on startup.
+         * @param showMenuIcons     [boolean] Specifies whether or not to show icon pictures in menus.
+         * @param editModeExclusive [boolean] Specifies whether or not to use exclusive edit mode (recommended on).
+         */
+       public EkitCore(boolean showViewSource, boolean showMenuIcons, boolean editModeExclusive)
+       {
+               this(null, null, null, null, showViewSource, showMenuIcons, editModeExclusive, null, null, false, false);
+       }
+
+       /** Language & Debug Constructor
+         * @param sLanguage [String]  The language portion of the Internationalization Locale to run Ekit in.
+         * @param sCountry  [String]  The country portion of the Internationalization Locale to run Ekit in.
+         * @param debugMode [boolean] Specifies whether to show the Debug menu or not.
+         */
+       public EkitCore(String sLanguage, String sCountry, boolean debugMode)
+       {
+               this(null, null, null, null, false, true, true, sLanguage, sCountry, false, debugMode);
+       }
+
+       /** Language Constructor
+         * @param sLanguage [String]  The language portion of the Internationalization Locale to run Ekit in.
+         * @param sCountry  [String]  The country portion of the Internationalization Locale to run Ekit in.
+         */
+       public EkitCore(String sLanguage, String sCountry)
+       {
+               this(null, null, null, null, false, true, true, sLanguage, sCountry, false, false);
+       }
+
+       /** Debug Constructor
+         * @param debugMode [boolean] Specifies whether to show the Debug menu or not.
+         */
+       public EkitCore(boolean debugMode)
+       {
+               this(null, null, null, null, false, true, true, null, null, false, debugMode);
+       }
+
+       /** Empty Constructor
+         */
+       public EkitCore()
+       {
+               this(null, null, null, null, false, true, true, null, null, false, false);
+       }
+
+       /* ActionListener method */
+       public void actionPerformed(ActionEvent ae)
+       {
+               try
+               {
+                       String command = ae.getActionCommand();
+                       if(command.equals("newdoc"))
+                       {
+                               SimpleInfoDialog sidAsk = new SimpleInfoDialog(this.getFrame(), "", true, Translatrix.getTranslationString("AskNewDocument"), SimpleInfoDialog.QUESTION);
+                               String decision = sidAsk.getDecisionValue();
+                               if(decision.equals(Translatrix.getTranslationString("DialogAccept")))
+                               {
+                                       if(styleSheet != null)
+                                       {
+                                               htmlDoc = new ExtendedHTMLDocument(styleSheet);
+                                       }
+                                       else
+                                       {
+                                               htmlDoc = (ExtendedHTMLDocument)(htmlKit.createDefaultDocument());
+                                       }
+                                       jtpMain.setText("<HTML><BODY></BODY></HTML>");
+                                       jtpSource.setText(jtpMain.getText());
+                                       registerDocument(htmlDoc);
+                                       currentFile = null;
+                                       updateTitle();
+                               }
+                       }
+                       else if(command.equals("openhtml"))
+                       {
+                               openDocument(null);
+                       }
+                       else if(command.equals("opencss"))
+                       {
+                               openStyleSheet(null);
+                       }
+                       else if(command.equals("openb64"))
+                       {
+                               openDocumentBase64(null);
+                       }
+                       else if(command.equals("save"))
+                       {
+                               writeOut((HTMLDocument)(jtpMain.getDocument()), currentFile);
+                               updateTitle();
+                       }
+                       else if(command.equals("saveas"))
+                       {
+                               writeOut((HTMLDocument)(jtpMain.getDocument()), null);
+                       }
+                       else if(command.equals("savebody"))
+                       {
+                               writeOutFragment((HTMLDocument)(jtpMain.getDocument()),"body");
+                       }
+                       else if(command.equals("savertf"))
+                       {
+                               writeOutRTF((StyledDocument)(jtpMain.getStyledDocument()));
+                       }
+                       else if(command.equals("saveb64"))
+                       {
+                               writeOutBase64(jtpSource.getText());
+                       }
+                       else if(command.equals("textcut"))
+                       {
+                               if(jspSource.isShowing() && jtpSource.hasFocus())
+                               {
+                                       jtpSource.cut();
+                               }
+                               else
+                               {
+                                       jtpMain.cut();
+                               }
+                       }
+                       else if(command.equals("textcopy"))
+                       {
+                               if(jspSource.isShowing() && jtpSource.hasFocus())
+                               {
+                                       jtpSource.copy();
+                               }
+                               else
+                               {
+                                       jtpMain.copy();
+                               }
+                       }
+                       else if(command.equals("textpaste"))
+                       {
+                               if(jspSource.isShowing() && jtpSource.hasFocus())
+                               {
+                                       jtpSource.paste();
+                               }
+                               else
+                               {
+                                       jtpMain.paste();
+                               }
+                       }
+                       else if(command.equals("describe"))
+                       {
+                               System.out.println("------------DOCUMENT------------");
+                               System.out.println("Content Type : " + jtpMain.getContentType());
+                               System.out.println("Editor Kit   : " + jtpMain.getEditorKit());
+                               System.out.println("Doc Tree     :");
+                               System.out.println("");
+                               describeDocument(jtpMain.getStyledDocument());
+                               System.out.println("--------------------------------");
+                               System.out.println("");
+                       }
+                       else if(command.equals("describecss"))
+                       {
+                               System.out.println("-----------STYLESHEET-----------");
+                               System.out.println("Stylesheet Rules");
+                               Enumeration rules = styleSheet.getStyleNames();
+                               while(rules.hasMoreElements())
+                               {
+                                       String ruleName = (String)(rules.nextElement());
+                                       Style styleRule = styleSheet.getStyle(ruleName);
+                                       System.out.println(styleRule.toString());
+                               }
+                               System.out.println("--------------------------------");
+                               System.out.println("");
+                       }
+                       else if(command.equals("whattags"))
+                       {
+                               System.out.println("Caret Position : " + jtpMain.getCaretPosition());
+                               AttributeSet attribSet = jtpMain.getCharacterAttributes();
+                               Enumeration attribs = attribSet.getAttributeNames();
+                               System.out.println("Attributes     : ");
+                               while(attribs.hasMoreElements())
+                               {
+                                       String attribName = attribs.nextElement().toString();
+                                       System.out.println("                 " + attribName + " | " + attribSet.getAttribute(attribName));
+                               }
+                       }
+                       else if(command.equals("toggletoolbar"))
+                       {
+                               jToolBar.setVisible(jcbmiViewToolbar.isSelected());
+                       }
+                       else if(command.equals("viewsource"))
+                       {
+                               toggleSourceWindow();
+                       }
+                       else if(command.equals("serialize"))
+                       {
+                               serializeOut((HTMLDocument)(jtpMain.getDocument()));
+                       }
+                       else if(command.equals("readfromser"))
+                       {
+                               serializeIn();
+                       }
+                       else if(command.equals("inserttable"))
+                       {
+                               String[] fieldNames = { "rows", "cols", "border", "cellspacing", "cellpadding", "width" };
+                               String[] fieldTypes = { "text", "text", "text",   "text",        "text",        "text" };
+                               insertTable((Hashtable)null, fieldNames, fieldTypes);
+                       }
+                       else if(command.equals("inserttablerow"))
+                       {
+                               insertTableRow();
+                       }
+                       else if(command.equals("inserttablecolumn"))
+                       {
+                               insertTableColumn();
+                       }
+                       else if(command.equals("deletetablerow"))
+                       {
+                               deleteTableRow();
+                       }
+                       else if(command.equals("deletetablecolumn"))
+                       {
+                               deleteTableColumn();
+                       }
+                       else if(command.equals("insertbreak"))
+                       {
+                               insertBreak();
+                       }
+                       else if(command.equals("insertlocalimage"))
+                       {
+                               insertLocalImage(null);
+                       }
+                       else if(command.equals("insertserverimage"))
+                       {
+                               insertServerImage();
+                       }
+                       else if(command.equals("insertnbsp"))
+                       {
+                               insertNonbreakingSpace();
+                       }
+                       else if(command.equals("insertform"))
+                       {
+                               String[] fieldNames  = { "name", "method",   "enctype" };
+                               String[] fieldTypes  = { "text", "combo",    "text" };
+                               String[] fieldValues = { "",     "POST,GET", "text" };
+                               insertFormElement(HTML.Tag.FORM, "form", (Hashtable)null, fieldNames, fieldTypes, fieldValues, true);
+                       }
+                       else if(command.equals("inserttextfield"))
+                       {
+                               Hashtable htAttribs = new Hashtable();
+                               htAttribs.put("type", "text");
+                               String[] fieldNames = { "name", "value", "size", "maxlength" };
+                               String[] fieldTypes = { "text", "text",  "text", "text" };
+                               insertFormElement(HTML.Tag.INPUT, "input", htAttribs, fieldNames, fieldTypes, false);
+                       }
+                       else if(command.equals("inserttextarea"))
+                       {
+                               String[] fieldNames = { "name", "rows", "cols" };
+                               String[] fieldTypes = { "text", "text", "text" };
+                               insertFormElement(HTML.Tag.TEXTAREA, "textarea", (Hashtable)null, fieldNames, fieldTypes, true);
+                       }
+                       else if(command.equals("insertcheckbox"))
+                       {
+                               Hashtable htAttribs = new Hashtable();
+                               htAttribs.put("type", "checkbox");
+                               String[] fieldNames = { "name", "checked" };
+                               String[] fieldTypes = { "text", "bool" };
+                               insertFormElement(HTML.Tag.INPUT, "input", htAttribs, fieldNames, fieldTypes, false);
+                       }
+                       else if(command.equals("insertradiobutton"))
+                       {
+                               Hashtable htAttribs = new Hashtable();
+                               htAttribs.put("type", "radio");
+                               String[] fieldNames = { "name", "checked" };
+                               String[] fieldTypes = { "text", "bool" };
+                               insertFormElement(HTML.Tag.INPUT, "input", htAttribs, fieldNames, fieldTypes, false);
+                       }
+                       else if(command.equals("insertpassword"))
+                       {
+                               Hashtable htAttribs = new Hashtable();
+                               htAttribs.put("type", "password");
+                               String[] fieldNames = { "name", "value", "size", "maxlength" };
+                               String[] fieldTypes = { "text", "text",  "text", "text" };
+                               insertFormElement(HTML.Tag.INPUT, "input", htAttribs, fieldNames, fieldTypes, false);
+                       }
+                       else if(command.equals("insertbutton"))
+                       {
+                               Hashtable htAttribs = new Hashtable();
+                               htAttribs.put("type", "button");
+                               String[] fieldNames = { "name", "value" };
+                               String[] fieldTypes = { "text", "text" };
+                               insertFormElement(HTML.Tag.INPUT, "input", htAttribs, fieldNames, fieldTypes, false);
+                       }
+                       else if(command.equals("insertbuttonsubmit"))
+                       {
+                               Hashtable htAttribs = new Hashtable();
+                               htAttribs.put("type", "submit");
+                               String[] fieldNames = { "name", "value" };
+                               String[] fieldTypes = { "text", "text" };
+                               insertFormElement(HTML.Tag.INPUT, "input", htAttribs, fieldNames, fieldTypes, false);
+                       }
+                       else if(command.equals("insertbuttonreset"))
+                       {
+                               Hashtable htAttribs = new Hashtable();
+                               htAttribs.put("type", "reset");
+                               String[] fieldNames = { "name", "value" };
+                               String[] fieldTypes = { "text", "text" };
+                               insertFormElement(HTML.Tag.INPUT, "input", htAttribs, fieldNames, fieldTypes, false);
+                       }
+                       else if(command.equals("find"))
+                       {
+                               doSearch((String)null, (String)null, false, lastSearchCaseSetting, lastSearchTopSetting);
+                       }
+                       else if(command.equals("findagain"))
+                       {
+                               doSearch(lastSearchFindTerm, (String)null, false, lastSearchCaseSetting, false);
+                       }
+                       else if(command.equals("replace"))
+                       {
+                               doSearch((String)null, (String)null, true, lastSearchCaseSetting, lastSearchTopSetting);
+                       }
+                       else if(command.equals("exit"))
+                       {
+                               this.dispose();
+                       }
+                       else if(command.equals("helpabout"))
+                       {
+                               SimpleInfoDialog sidAbout = new SimpleInfoDialog(this.getFrame(), Translatrix.getTranslationString("About"), true, Translatrix.getTranslationString("AboutMessage"), SimpleInfoDialog.INFO);
+                       }
+               }
+               catch(IOException ioe)
+               {
+                       logException("IOException in actionPerformed method", ioe);
+                       SimpleInfoDialog sidAbout = new SimpleInfoDialog(this.getFrame(), Translatrix.getTranslationString("Error"), true, Translatrix.getTranslationString("ErrorIOException"), SimpleInfoDialog.ERROR);
+               }
+               catch(BadLocationException ble)
+               {
+                       logException("BadLocationException in actionPerformed method", ble);
+                       SimpleInfoDialog sidAbout = new SimpleInfoDialog(this.getFrame(), Translatrix.getTranslationString("Error"), true, Translatrix.getTranslationString("ErrorBadLocationException"), SimpleInfoDialog.ERROR);
+               }
+               catch(NumberFormatException nfe)
+               {
+                       logException("NumberFormatException in actionPerformed method", nfe);
+                       SimpleInfoDialog sidAbout = new SimpleInfoDialog(this.getFrame(), Translatrix.getTranslationString("Error"), true, Translatrix.getTranslationString("ErrorNumberFormatException"), SimpleInfoDialog.ERROR);
+               }
+               catch(ClassNotFoundException cnfe)
+               {
+                       logException("ClassNotFound Exception in actionPerformed method", cnfe);
+                       SimpleInfoDialog sidAbout = new SimpleInfoDialog(this.getFrame(), Translatrix.getTranslationString("Error"), true, Translatrix.getTranslationString("ErrorClassNotFoundException "), SimpleInfoDialog.ERROR);
+               }
+               catch(RuntimeException re)
+               {
+                       logException("RuntimeException in actionPerformed method", re);
+                       SimpleInfoDialog sidAbout = new SimpleInfoDialog(this.getFrame(), Translatrix.getTranslationString("Error"), true, Translatrix.getTranslationString("ErrorRuntimeException"), SimpleInfoDialog.ERROR);
+               }
+       }
+
+       /* KeyListener methods */
+       public void keyTyped(KeyEvent ke)
+       {
+               Element elem;
+               String selectedText;
+               int pos = this.getCaretPosition();
+               int repos = -1;
+               if(ke.getKeyChar() == KeyEvent.VK_BACK_SPACE)
+               {
+                       try
+                       {
+                               if(pos > 0)
+                               {
+                                       if((selectedText = jtpMain.getSelectedText()) != null)
+                                       {
+                                               htmlUtilities.delete();
+                                               return;
+                                       }
+                                       else
+                                       {
+                                               int sOffset = htmlDoc.getParagraphElement(pos).getStartOffset();
+                                               if(sOffset == jtpMain.getSelectionStart())
+                                               {
+                                                       boolean content = true;
+                                                       if(htmlUtilities.checkParentsTag(HTML.Tag.LI))
+                                                       {
+                                                               elem = htmlUtilities.getListItemParent();
+                                                               content = false;
+                                                               int so = elem.getStartOffset();
+                                                               int eo = elem.getEndOffset();
+                                                               if(so + 1 < eo)
+                                                               {
+                                                                       char[] temp = jtpMain.getText(so, eo - so).toCharArray();
+                                                                       for(int i=0; i < temp.length; i++)
+                                                                       {
+                                                                               if(!(new Character(temp[i])).isWhitespace(temp[i]))
+                                                                               {
+                                                                                       content = true;
+                                                                               }
+                                                                       }
+                                                               }
+                                                               if(!content)
+                                                               {
+                                                                       Element listElement = elem.getParentElement();
+                                                                       htmlUtilities.removeTag(elem, true);
+                                                                       this.setCaretPosition(sOffset - 1);
+                                                                       return;
+                                                               }
+                                                               else
+                                                               {
+                                                                       jtpMain.setCaretPosition(jtpMain.getCaretPosition() - 1);
+                                                                       jtpMain.moveCaretPosition(jtpMain.getCaretPosition() - 2);
+                                                                       jtpMain.replaceSelection("");
+                                                                       return;
+                                                               }
+                                                       }
+                                                       else if(htmlUtilities.checkParentsTag(HTML.Tag.TABLE))
+                                                       {
+                                                               jtpMain.setCaretPosition(jtpMain.getCaretPosition() - 1);
+                                                               ke.consume();
+                                                               return;
+                                                       }
+                                               }
+                                               jtpMain.replaceSelection("");
+                                               return;
+                                       }
+                               }
+                       }
+                       catch (BadLocationException ble)
+                       {
+                               logException("BadLocationException in keyTyped method", ble);
+                               SimpleInfoDialog sidAbout = new SimpleInfoDialog(this.getFrame(), Translatrix.getTranslationString("Error"), true, Translatrix.getTranslationString("ErrorBadLocationException"), SimpleInfoDialog.ERROR);
+                       }
+                       catch (IOException ioe)
+                       {
+                               logException("IOException in keyTyped method", ioe);
+                               SimpleInfoDialog sidAbout = new SimpleInfoDialog(this.getFrame(), Translatrix.getTranslationString("Error"), true, Translatrix.getTranslationString("ErrorIOException"), SimpleInfoDialog.ERROR);
+                       }
+               }
+               else if(ke.getKeyChar() == KeyEvent.VK_ENTER)
+               {
+                       try
+                       {
+                               if(htmlUtilities.checkParentsTag(HTML.Tag.UL) == true | htmlUtilities.checkParentsTag(HTML.Tag.OL) == true)
+                               {
+                                       elem = htmlUtilities.getListItemParent();
+                                       int so = elem.getStartOffset();
+                                       int eo = elem.getEndOffset();
+                                       char[] temp = this.getTextPane().getText(so,eo-so).toCharArray();
+                                       boolean content = false;
+                                       for(int i=0;i<temp.length;i++)
+                                       {
+                                               if(!(new Character(temp[i])).isWhitespace(temp[i]))
+                                               {
+                                                       content = true;
+                                               }
+                                       }
+                                       if(content)
+                                       {
+                                               int end = -1;
+                                               int j = temp.length;
+                                               do
+                                               {
+                                                       j--;
+                                                       if(new Character(temp[j]).isLetterOrDigit(temp[j]))
+                                                       {
+                                                               end = j;
+                                                       }
+                                               } while (end == -1 && j >= 0);
+                                               j = end;
+                                               do
+                                               {
+                                                       j++;
+                                                       if(!new Character(temp[j]).isSpaceChar(temp[j]))
+                                                       {
+                                                               repos = j - end -1;
+                                                       }
+                                               } while (repos == -1 && j < temp.length);
+                                               if(repos == -1)
+                                               {
+                                                       repos = 0;
+                                               }
+                                       }
+                                       if(elem.getStartOffset() == elem.getEndOffset() || !content)
+                                       {
+                                               manageListElement(elem);
+                                       }
+                                       else
+                                       {
+                                               if(this.getCaretPosition() + 1 == elem.getEndOffset())
+                                               {
+                                                       insertListStyle(elem);
+                                                       this.setCaretPosition(pos - repos);
+                                               }
+                                               else
+                                               {
+                                                       int caret = this.getCaretPosition();
+                                                       String tempString = this.getTextPane().getText(caret, eo - caret);
+                                                       this.getTextPane().select(caret, eo - 1);
+                                                       this.getTextPane().replaceSelection("");
+                                                       htmlUtilities.insertListElement(tempString);
+                                                       Element newLi = htmlUtilities.getListItemParent();
+                                                       this.setCaretPosition(newLi.getEndOffset() - 1);
+                                               }
+                                       }
+                               }
+                       }
+                       catch (BadLocationException ble)
+                       {
+                               logException("BadLocationException in keyTyped method", ble);
+                               SimpleInfoDialog sidAbout = new SimpleInfoDialog(this.getFrame(), Translatrix.getTranslationString("Error"), true, Translatrix.getTranslationString("ErrorBadLocationException"), SimpleInfoDialog.ERROR);
+                       }
+                       catch (IOException ioe)
+                       {
+                               logException("IOException in keyTyped method", ioe);
+                               SimpleInfoDialog sidAbout = new SimpleInfoDialog(this.getFrame(), Translatrix.getTranslationString("Error"), true, Translatrix.getTranslationString("ErrorIOException"), SimpleInfoDialog.ERROR);
+                       }
+               }
+       }
+       public void keyPressed(KeyEvent e) {}
+       public void keyReleased(KeyEvent e) {}
+
+       public void insertListStyle(Element element)
+       throws BadLocationException,IOException
+       {
+               if(element.getParentElement().getName() == "ol")
+               {
+                       actionListOrdered.actionPerformed(new ActionEvent(new Object(), 0, "newListPoint"));
+               }
+               else
+               {
+                       actionListUnordered.actionPerformed(new ActionEvent(new Object(), 0, "newListPoint"));
+               }
+       }
+
+       /* DocumentListener methods */
+       public void changedUpdate(DocumentEvent de)     { handleDocumentChange(de); }
+       public void insertUpdate(DocumentEvent de)      { handleDocumentChange(de); }
+       public void removeUpdate(DocumentEvent de)      { handleDocumentChange(de); }
+       public void handleDocumentChange(DocumentEvent de)
+       {
+               if(!exclusiveEdit)
+               {
+                       if(jspSource.isShowing())
+                       {
+                               if(de.getDocument() instanceof HTMLDocument || de.getDocument() instanceof ExtendedHTMLDocument)
+                               {
+                                       jtpSource.getDocument().removeDocumentListener(this);
+                                       jtpSource.setText(jtpMain.getText());
+                                       jtpSource.getDocument().addDocumentListener(this);
+                               }
+                               else if(de.getDocument() instanceof PlainDocument || de.getDocument() instanceof DefaultStyledDocument)
+                               {
+                                       jtpMain.getDocument().removeDocumentListener(this);
+                                       jtpMain.setText(jtpSource.getText());
+                                       jtpMain.getDocument().addDocumentListener(this);
+                               }
+                       }
+               }
+       }
+
+       /** Method for setting a document as the current document for the text pane
+         * and re-registering the controls and settings for it
+         */
+       public void registerDocument(ExtendedHTMLDocument htmlDoc)
+       {
+               jtpMain.setDocument(htmlDoc);
+               jtpMain.getDocument().addUndoableEditListener(new CustomUndoableEditListener());
+               jtpMain.getDocument().addDocumentListener(this);
+               purgeUndos();
+               registerDocumentStyles();
+       }
+
+       /** Method for locating the available CSS style for the document and adding
+         * them to the styles selector
+         */
+       public void registerDocumentStyles()
+       {
+               if(jcmbStyleSelector == null || htmlDoc == null)
+               {
+                       return;
+               }
+               jcmbStyleSelector.setEnabled(false);
+               jcmbStyleSelector.removeAllItems();
+               jcmbStyleSelector.addItem(Translatrix.getTranslationString("NoCSSStyle"));
+               for(Enumeration e = htmlDoc.getStyleNames(); e.hasMoreElements();)
+               {
+                       String name = (String) e.nextElement();
+                       if(name.length() > 0 && name.charAt(0) == '.')
+                       {
+                               jcmbStyleSelector.addItem(name.substring(1));
+                       }
+               }
+               jcmbStyleSelector.setEnabled(true);
+       }
+
+       /** Method for inserting an HTML Table
+         */
+       private void insertTable(Hashtable attribs, String[] fieldNames, String[] fieldTypes)
+       throws IOException, BadLocationException, RuntimeException, NumberFormatException
+       {
+               int caretPos = jtpMain.getCaretPosition();
+               StringBuffer compositeElement = new StringBuffer("<TABLE");
+               if(attribs != null && attribs.size() > 0)
+               {
+                       Enumeration attribEntries = attribs.keys();
+                       while(attribEntries.hasMoreElements())
+                       {
+                               Object entryKey   = attribEntries.nextElement();
+                               Object entryValue = attribs.get(entryKey);
+                               if(entryValue != null && entryValue != "")
+                               {
+                                       compositeElement.append(" " + entryKey + "=" + '"' + entryValue + '"');
+                               }
+                       }
+               }
+               int rows = 0;
+               int cols = 0;
+               if(fieldNames != null && fieldNames.length > 0)
+               {
+                       PropertiesDialog propertiesDialog = new PropertiesDialog(this.getFrame(), fieldNames, fieldTypes, Translatrix.getTranslationString("FormDialogTitle"), true);
+                       propertiesDialog.show();
+                       String decision = propertiesDialog.getDecisionValue();
+                       if(decision.equals(Translatrix.getTranslationString("DialogCancel")))
+                       {
+                               propertiesDialog.dispose();
+                               propertiesDialog = null;
+                               return;
+                       }
+                       else
+                       {
+                               for(int iter = 0; iter < fieldNames.length; iter++)
+                               {
+                                       String fieldName = fieldNames[iter];
+                                       String propValue = propertiesDialog.getFieldValue(fieldName);
+                                       if(propValue != null && propValue != "" && propValue.length() > 0)
+                                       {
+                                               if(fieldName.equals("rows"))
+                                               {
+                                                       rows = Integer.parseInt(propValue);
+                                               }
+                                               else if(fieldName.equals("cols"))
+                                               {
+                                                       cols = Integer.parseInt(propValue);
+                                               }
+                                               else
+                                               {
+                                                       compositeElement.append(" " + fieldName + "=" + '"' + propValue + '"');
+                                               }
+                                       }
+                               }
+                       }
+                       propertiesDialog.dispose();
+                       propertiesDialog = null;
+               }
+               compositeElement.append(">");
+               for(int i = 0; i < rows; i++)
+               {
+                       compositeElement.append("<TR>");
+                       for(int j = 0; j < cols; j++)
+                       {
+                               compositeElement.append("<TD></TD>");
+                       }
+                       compositeElement.append("</TR>");
+               }
+               compositeElement.append("</TABLE><P>&nbsp;<P>");
+               htmlKit.insertHTML(htmlDoc, caretPos, compositeElement.toString(), 0, 0, HTML.Tag.TABLE);
+               jtpMain.setCaretPosition(caretPos + 1);
+               refreshOnUpdate();
+       }
+
+       /** Method for inserting a row into an HTML Table
+         */
+       private void insertTableRow()
+       {
+               int caretPos = jtpMain.getCaretPosition();
+               Element element = htmlDoc.getCharacterElement(jtpMain.getCaretPosition());
+               Element elementParent = element.getParentElement();
+               int startPoint  = -1;
+               int columnCount = -1;
+               while(elementParent != null && !elementParent.getName().equals("body"))
+               {
+                       if(elementParent.getName().equals("tr"))
+                       {
+                               startPoint  = elementParent.getStartOffset();
+                               columnCount = elementParent.getElementCount();
+                               break;
+                       }
+                       else
+                       {
+                               elementParent = elementParent.getParentElement();
+                       }
+               }
+               if(startPoint > -1 && columnCount > -1)
+               {
+                       jtpMain.setCaretPosition(startPoint);
+                       StringBuffer sRow = new StringBuffer();
+                       sRow.append("<TR>");
+                       for(int i = 0; i < columnCount; i++)
+                       {
+                               sRow.append("<TD></TD>");
+                       }
+                       sRow.append("</TR>");
+                       ActionEvent actionEvent = new ActionEvent(jtpMain, 0, "insertTableRow");
+                       new HTMLEditorKit.InsertHTMLTextAction("insertTableRow", sRow.toString(), HTML.Tag.TABLE, HTML.Tag.TR).actionPerformed(actionEvent);
+                       refreshOnUpdate();
+                       jtpMain.setCaretPosition(caretPos);
+               }
+       }
+
+       /** Method for inserting a column into an HTML Table
+         */
+       private void insertTableColumn()
+       {
+               int caretPos = jtpMain.getCaretPosition();
+               Element element = htmlDoc.getCharacterElement(jtpMain.getCaretPosition());
+               Element elementParent = element.getParentElement();
+               int startPoint = -1;
+               int rowCount   = -1;
+               int cellOffset =  0;
+               while(elementParent != null && !elementParent.getName().equals("body"))
+               {
+                       if(elementParent.getName().equals("table"))
+                       {
+                               startPoint = elementParent.getStartOffset();
+                               rowCount   = elementParent.getElementCount();
+                               break;
+                       }
+                       else if(elementParent.getName().equals("tr"))
+                       {
+                               int rowStart = elementParent.getStartOffset();
+                               int rowCells = elementParent.getElementCount();
+                               for(int i = 0; i < rowCells; i++)
+                               {
+                                       Element currentCell = elementParent.getElement(i);
+                                       if(jtpMain.getCaretPosition() >= currentCell.getStartOffset() && jtpMain.getCaretPosition() <= currentCell.getEndOffset())
+                                       {
+                                               cellOffset = i;
+                                       }
+                               }
+                               elementParent = elementParent.getParentElement();
+                       }
+                       else
+                       {
+                               elementParent = elementParent.getParentElement();
+                       }
+               }
+               if(startPoint > -1 && rowCount > -1)
+               {
+                       jtpMain.setCaretPosition(startPoint);
+                       String sCell = "<TD></TD>";
+                       ActionEvent actionEvent = new ActionEvent(jtpMain, 0, "insertTableCell");
+                       for(int i = 0; i < rowCount; i++)
+                       {
+                               Element row = elementParent.getElement(i);
+                               Element whichCell = row.getElement(cellOffset);
+                               jtpMain.setCaretPosition(whichCell.getStartOffset());
+                               new HTMLEditorKit.InsertHTMLTextAction("insertTableCell", sCell, HTML.Tag.TR, HTML.Tag.TD, HTML.Tag.TH, HTML.Tag.TD).actionPerformed(actionEvent);
+                       }
+                       refreshOnUpdate();
+                       jtpMain.setCaretPosition(caretPos);
+               }
+       }
+
+       /** Method for inserting a cell into an HTML Table
+         */
+       private void insertTableCell()
+       {
+               String sCell = "<TD></TD>";
+               ActionEvent actionEvent = new ActionEvent(jtpMain, 0, "insertTableCell");
+               new HTMLEditorKit.InsertHTMLTextAction("insertTableCell", sCell, HTML.Tag.TR, HTML.Tag.TD, HTML.Tag.TH, HTML.Tag.TD).actionPerformed(actionEvent);
+               refreshOnUpdate();
+       }
+
+       /** Method for deleting a row from an HTML Table
+         */
+       private void deleteTableRow()
+       throws BadLocationException
+       {
+               int caretPos = jtpMain.getCaretPosition();
+               Element element = htmlDoc.getCharacterElement(jtpMain.getCaretPosition());
+               Element elementParent = element.getParentElement();
+               int startPoint = -1;
+               int endPoint   = -1;
+               while(elementParent != null && !elementParent.getName().equals("body"))
+               {
+                       if(elementParent.getName().equals("tr"))
+                       {
+                               startPoint = elementParent.getStartOffset();
+                               endPoint   = elementParent.getEndOffset();
+                               break;
+                       }
+                       else
+                       {
+                               elementParent = elementParent.getParentElement();
+                       }
+               }
+               if(startPoint > -1 && endPoint > startPoint)
+               {
+                       htmlDoc.remove(startPoint, endPoint - startPoint);
+                       jtpMain.setDocument(htmlDoc);
+                       registerDocument(htmlDoc);
+                       refreshOnUpdate();
+                       if(caretPos >= htmlDoc.getLength())
+                       {
+                               caretPos = htmlDoc.getLength() - 1;
+                       }
+                       jtpMain.setCaretPosition(caretPos);
+               }
+       }
+
+       /** Method for deleting a column from an HTML Table
+         */
+       private void deleteTableColumn()
+       throws BadLocationException
+       {
+               int caretPos = jtpMain.getCaretPosition();
+               Element element       = htmlDoc.getCharacterElement(jtpMain.getCaretPosition());
+               Element elementParent = element.getParentElement();
+               Element elementCell   = (Element)null;
+               Element elementRow    = (Element)null;
+               Element elementTable  = (Element)null;
+               // Locate the table, row, and cell location of the cursor
+               while(elementParent != null && !elementParent.getName().equals("body"))
+               {
+                       if(elementParent.getName().equals("td"))
+                       {
+                               elementCell = elementParent;
+                       }
+                       else if(elementParent.getName().equals("tr"))
+                       {
+                               elementRow = elementParent;
+                       }
+                       else if(elementParent.getName().equals("table"))
+                       {
+                               elementTable = elementParent;
+                       }
+                       elementParent = elementParent.getParentElement();
+               }
+               int whichColumn = -1;
+               if(elementCell != null && elementRow != null && elementTable != null)
+               {
+                       // Find the column the cursor is in
+                       for(int i = 0; i < elementRow.getElementCount(); i++)
+                       {
+                               if(elementCell == elementRow.getElement(i))
+                               {
+                                       whichColumn = i;
+                               }
+                       }
+                       if(whichColumn > -1)
+                       {
+                               // Iterate through the table rows, deleting cells from the indicated column
+                               for(int i = 0; i < elementTable.getElementCount(); i++)
+                               {
+                                       elementRow  = elementTable.getElement(i);
+                                       elementCell = (elementRow.getElementCount() > whichColumn ? elementRow.getElement(whichColumn) : elementRow.getElement(elementRow.getElementCount() - 1));
+                                       int columnCellStart = elementCell.getStartOffset();
+                                       int columnCellEnd   = elementCell.getEndOffset();
+                                       htmlDoc.remove(columnCellStart, columnCellEnd - columnCellStart);
+                               }
+                               jtpMain.setDocument(htmlDoc);
+                               registerDocument(htmlDoc);
+                               refreshOnUpdate();
+                               if(caretPos >= htmlDoc.getLength())
+                               {
+                                       caretPos = htmlDoc.getLength() - 1;
+                               }
+                               jtpMain.setCaretPosition(caretPos);
+                       }
+               }
+       }
+
+       /** Method for inserting a break (BR) element
+         */
+       private void insertBreak()
+       throws IOException, BadLocationException, RuntimeException
+       {
+               int caretPos = jtpMain.getCaretPosition();
+               htmlKit.insertHTML(htmlDoc, caretPos, "<BR>", 0, 0, HTML.Tag.BR);
+               jtpMain.setCaretPosition(caretPos + 1);
+       }
+
+       /** Method for inserting a non-breaking space (&nbsp;)
+         */
+       private void insertNonbreakingSpace()
+       throws IOException, BadLocationException, RuntimeException
+       {
+               int caretPos = jtpMain.getCaretPosition();
+               htmlDoc.insertString(caretPos, "\240", jtpMain.getInputAttributes());
+               jtpMain.setCaretPosition(caretPos + 1);
+       }
+
+       /** Method for inserting a form element
+         */
+       private void insertFormElement(HTML.Tag baseTag, String baseElement, Hashtable attribs, String[] fieldNames, String[] fieldTypes, String[] fieldValues, boolean hasClosingTag)
+       throws IOException, BadLocationException, RuntimeException
+       {
+               int caretPos = jtpMain.getCaretPosition();
+               StringBuffer compositeElement = new StringBuffer("<" + baseElement);
+               if(attribs != null && attribs.size() > 0)
+               {
+                       Enumeration attribEntries = attribs.keys();
+                       while(attribEntries.hasMoreElements())
+                       {
+                               Object entryKey   = attribEntries.nextElement();
+                               Object entryValue = attribs.get(entryKey);
+                               if(entryValue != null && entryValue != "")
+                               {
+                                       compositeElement.append(" " + entryKey + "=" + '"' + entryValue + '"');
+                               }
+                       }
+               }
+               if(fieldNames != null && fieldNames.length > 0)
+               {
+                       PropertiesDialog propertiesDialog = new PropertiesDialog(this.getFrame(), fieldNames, fieldTypes, fieldValues, Translatrix.getTranslationString("FormDialogTitle"), true);
+                       propertiesDialog.show();
+                       String decision = propertiesDialog.getDecisionValue();
+                       if(decision.equals(Translatrix.getTranslationString("DialogCancel")))
+                       {
+                               propertiesDialog.dispose();
+                               propertiesDialog = null;
+                               return;
+                       }
+                       else
+                       {
+                               for(int iter = 0; iter < fieldNames.length; iter++)
+                               {
+                                       String fieldName = fieldNames[iter];
+                                       String propValue = propertiesDialog.getFieldValue(fieldName);
+                                       if(propValue != null && propValue.length() > 0)
+                                       {
+                                               if(fieldName.equals("checked"))
+                                               {
+                                                       if(propValue.equals("true"))
+                                                       {
+                                                               compositeElement.append(" " + fieldName + "=" + '"' + propValue + '"');
+                                                       }
+                                               }
+                                               else
+                                               {
+                                                       compositeElement.append(" " + fieldName + "=" + '"' + propValue + '"');
+                                               }
+                                       }
+                               }
+                       }
+                       propertiesDialog.dispose();
+                       propertiesDialog = null;
+               }
+               // --- Convenience for editing, this makes the FORM visible
+               if(useFormIndicator && baseElement.equals("form"))
+               {
+                       compositeElement.append(" bgcolor=" + '"' + clrFormIndicator + '"');
+               }
+               // --- END
+               compositeElement.append(">");
+               if(hasClosingTag)
+               {
+                       compositeElement.append("</" + baseElement + ">");
+               }
+               if(baseTag == HTML.Tag.FORM)
+               {
+                       compositeElement.append("<P>&nbsp;</P>");
+               }
+               htmlKit.insertHTML(htmlDoc, caretPos, compositeElement.toString(), 0, 0, baseTag);
+               // jtpMain.setCaretPosition(caretPos + 1);
+               refreshOnUpdate();
+       }
+
+       /** Alternate method call for inserting a form element
+         */
+       private void insertFormElement(HTML.Tag baseTag, String baseElement, Hashtable attribs, String[] fieldNames, String[] fieldTypes, boolean hasClosingTag)
+       throws IOException, BadLocationException, RuntimeException
+       {
+               insertFormElement(baseTag, baseElement, attribs, fieldNames, fieldTypes, new String[fieldNames.length], hasClosingTag);
+       }
+
+       /** Method that handles initial list insertion and deletion
+         */
+       public void manageListElement(Element element)
+       {
+               Element h = htmlUtilities.getListItemParent();
+               Element listElement = h.getParentElement();
+               if(h != null)
+               {
+                       htmlUtilities.removeTag(h, true);
+               }
+       }
+
+       /** Method to initiate a find/replace operation
+         */
+       private void doSearch(String searchFindTerm, String searchReplaceTerm, boolean bIsFindReplace, boolean bCaseSensitive, boolean bStartAtTop)
+       {
+               boolean bReplaceAll = false;
+               JTextPane searchPane = jtpMain;
+               if(jspSource.isShowing() || jtpSource.hasFocus())
+               {
+                       searchPane = jtpSource;
+               }
+               if(searchFindTerm == null || (bIsFindReplace && searchReplaceTerm == null))
+               {
+                       SearchDialog sdSearchInput = new SearchDialog(this.getFrame(), Translatrix.getTranslationString("SearchDialogTitle"), true, bIsFindReplace, bCaseSensitive, bStartAtTop);
+                       searchFindTerm    = sdSearchInput.getFindTerm();
+                       searchReplaceTerm = sdSearchInput.getReplaceTerm();
+                       bCaseSensitive    = sdSearchInput.getCaseSensitive();
+                       bStartAtTop       = sdSearchInput.getStartAtTop();
+                       bReplaceAll       = sdSearchInput.getReplaceAll();
+               }
+               if(searchFindTerm != null && (!bIsFindReplace || searchReplaceTerm != null))
+               {
+                       if(bReplaceAll)
+                       {
+                               int results = findText(searchFindTerm, searchReplaceTerm, bCaseSensitive, 0);
+                               int findOffset = 0;
+                               if(results > -1)
+                               {
+                                       while(results > -1)
+                                       {
+                                               findOffset = findOffset + searchReplaceTerm.length();
+                                               results    = findText(searchFindTerm, searchReplaceTerm, bCaseSensitive, findOffset);
+                                       }
+                               }
+                               else
+                               {
+                                       SimpleInfoDialog sidWarn = new SimpleInfoDialog(this.getFrame(), "", true, Translatrix.getTranslationString("ErrorNoOccurencesFound") + ":\n" + searchFindTerm, SimpleInfoDialog.WARNING);
+                               }
+                       }
+                       else
+                       {
+                               int results = findText(searchFindTerm, searchReplaceTerm, bCaseSensitive, (bStartAtTop ? 0 : searchPane.getCaretPosition()));
+                               if(results == -1)
+                               {
+                                       SimpleInfoDialog sidWarn = new SimpleInfoDialog(this.getFrame(), "", true, Translatrix.getTranslationString("ErrorNoMatchFound") + ":\n" + searchFindTerm, SimpleInfoDialog.WARNING);
+                               }
+                       }
+                       lastSearchFindTerm    = new String(searchFindTerm);
+                       if(searchReplaceTerm != null)
+                       {
+                               lastSearchReplaceTerm = new String(searchReplaceTerm);
+                       }
+                       else
+                       {
+                               lastSearchReplaceTerm = (String)null;
+                       }
+                       lastSearchCaseSetting = bCaseSensitive;
+                       lastSearchTopSetting  = bStartAtTop;
+               }
+       }
+
+       /** Method for finding (and optionally replacing) a string in the text
+         */
+       private int findText(String findTerm, String replaceTerm, boolean bCaseSenstive, int iOffset)
+       {
+               JTextPane jtpFindSource;
+               if(jspSource.isShowing() || jtpSource.hasFocus())
+               {
+                       jtpFindSource = jtpSource;
+               }
+               else
+               {
+                       jtpFindSource = jtpMain;
+               }
+               int searchPlace = -1;
+               try
+               {
+                       Document baseDocument = jtpFindSource.getDocument();
+                       searchPlace =
+                               (bCaseSenstive ?
+                                       baseDocument.getText(0, baseDocument.getLength()).indexOf(findTerm, iOffset) :
+                                       baseDocument.getText(0, baseDocument.getLength()).toLowerCase().indexOf(findTerm.toLowerCase(), iOffset)
+                               );
+                       if(searchPlace > -1)
+                       {
+                               if(replaceTerm != null)
+                               {
+                                       AttributeSet attribs = null;
+                                       if(baseDocument instanceof HTMLDocument)
+                                       {
+                                               Element element = ((HTMLDocument)baseDocument).getCharacterElement(searchPlace);
+                                               attribs = element.getAttributes();
+                                       }
+                                       baseDocument.remove(searchPlace, findTerm.length());
+                                       baseDocument.insertString(searchPlace, replaceTerm, attribs);
+                                       jtpFindSource.setCaretPosition(searchPlace + replaceTerm.length());
+                                       jtpFindSource.requestFocus();
+                                       jtpFindSource.select(searchPlace, searchPlace + replaceTerm.length());
+                               }
+                               else
+                               {
+                                       jtpFindSource.setCaretPosition(searchPlace + findTerm.length());
+                                       jtpFindSource.requestFocus();
+                                       jtpFindSource.select(searchPlace, searchPlace + findTerm.length());
+                               }
+                       }
+               }
+               catch(BadLocationException ble)
+               {
+                       logException("BadLocationException in actionPerformed method", ble);
+                       SimpleInfoDialog sidAbout = new SimpleInfoDialog(this.getFrame(), Translatrix.getTranslationString("Error"), true, Translatrix.getTranslationString("ErrorBadLocationException"), SimpleInfoDialog.ERROR);
+               }
+               return searchPlace;
+       }
+
+       /** Method for inserting an image from a file
+         */
+       private void insertLocalImage(File whatImage)
+       throws IOException, BadLocationException, RuntimeException
+       {
+               if(whatImage == null)
+               {
+                       whatImage = getImageFromChooser(".", extsIMG, Translatrix.getTranslationString("FiletypeIMG"));
+               }
+               if(whatImage != null)
+               {
+                       int caretPos = jtpMain.getCaretPosition();
+                       htmlKit.insertHTML(htmlDoc, caretPos, "<IMG SRC=\"" + whatImage + "\">", 0, 0, HTML.Tag.IMG);
+                       jtpMain.setCaretPosition(caretPos + 1);
+                       refreshOnUpdate();
+               }
+       }
+
+       /** Method for inserting an image from a server
+         */
+       private void insertServerImage()
+       throws BadLocationException
+       {
+               if(ServletURL != null)
+               {
+                       try
+                       {
+                               URL theServlet = new URL(ServletURL + "?GetImages=" + TreePilotSystemID + "&ImageExtensions=" + TreePilotProperties.getString("ValidImageExtensions"));
+                               URLConnection conn = theServlet.openConnection();
+                               ObjectInputStream in = new ObjectInputStream(conn.getInputStream());
+                               String[] imageList = (String[]) in.readObject();
+                               int caretPos = jtpMain.getCaretPosition();
+                               ImageDialog imageDialog = new ImageDialog(this, ImageDir + TreePilotSystemID, imageList, "Image Chooser", true);
+                               String selectedImage = imageDialog.getSelectedImage();
+                               imageDialog.dispose();
+                               if(selectedImage != null  && !selectedImage.equals(""))
+                               {
+                                       htmlKit.insertHTML(htmlDoc, caretPos, selectedImage, 0, 0, HTML.Tag.IMG);
+                                       jtpMain.setCaretPosition(caretPos + 1);
+                               }
+                               jtpMain.requestFocus();
+                               in.close();
+                       }
+                       catch (MalformedURLException mue)
+                       {
+                               System.err.println("MalFormedURLException during insertImage " + mue);
+                       }
+                       catch (IOException ie)
+                       {
+                               System.err.println("IOException during insertImage " + ie);
+                       }
+                       catch (ClassNotFoundException cnfe)
+                       {
+                               System.err.println("ClassNotFoundException during insertImage" + cnfe);
+                       }
+               }
+       }
+
+       /** Method for inserting an image
+         */
+       public String insertFile()
+       {
+               String selectedFile = null;
+               if(ServletURL != null)
+               {
+                       try
+                       {
+                               URL theServlet = new URL(ServletURL + "?GetFiles=" + TreePilotSystemID + "&FileExtensions=" + TreePilotProperties.getString("ValidFileExtensions"));
+                               URLConnection conn = theServlet.openConnection();
+                               ObjectInputStream in = new ObjectInputStream(conn.getInputStream());
+                               String[] fileList = (String[]) in.readObject();
+                               FileDialog fileDialog = new FileDialog(this, ImageDir + TreePilotSystemID, fileList, "File Chooser", true);
+                               selectedFile = fileDialog.getSelectedFile();
+                               fileDialog.dispose();
+                               in.close();
+                       }
+                       catch (MalformedURLException mue)
+                       {
+                               System.err.println("MalFormedURLException during insertFile " + mue);
+                       }
+                       catch (IOException ie)
+                       {
+                               System.err.println("IOException during insertFile " + ie);
+                       }
+                       catch (ClassNotFoundException cnfe)
+                       {
+                               System.err.println("ClassNotFoundException during insertFile" + cnfe);
+                       }
+               }
+               return selectedFile;
+       }
+
+       /** Method for saving text as a complete HTML document
+         */
+       private void writeOut(HTMLDocument doc, File whatFile)
+       throws IOException, BadLocationException
+       {
+               if(whatFile == null)
+               {
+                       whatFile = getFileFromChooser(".", JFileChooser.SAVE_DIALOG, extsHTML, Translatrix.getTranslationString("FiletypeHTML"));
+               }
+               if(whatFile != null)
+               {
+                       FileWriter fw = new FileWriter(whatFile);
+                       htmlKit.write(fw, doc, 0, doc.getLength());
+                       fw.flush();
+                       fw.close();
+                       currentFile = whatFile;
+                       updateTitle();
+               }
+               refreshOnUpdate();
+       }
+
+       /** Method for saving text as an HTML fragment
+         */
+       private void writeOutFragment(HTMLDocument doc, String containingTag)
+       throws IOException, BadLocationException
+       {
+               File whatFile = getFileFromChooser(".", JFileChooser.SAVE_DIALOG, extsHTML, Translatrix.getTranslationString("FiletypeHTML"));
+               if(whatFile != null)
+               {
+                       FileWriter fw = new FileWriter(whatFile);
+//                     Element eleBody = locateElementInDocument((StyledDocument)doc, containingTag);
+//                     htmlKit.write(fw, doc, eleBody.getStartOffset(), eleBody.getEndOffset());
+                       String docTextCase = jtpSource.getText().toLowerCase();
+                       int tagStart       = docTextCase.indexOf("<" + containingTag.toLowerCase());
+                       int tagStartClose  = docTextCase.indexOf(">", tagStart) + 1;
+                       String closeTag    = "</" + containingTag.toLowerCase() + ">";
+                       int tagEndOpen     = docTextCase.indexOf(closeTag);
+                       if(tagStartClose < 0) { tagStartClose = 0; }
+                       if(tagEndOpen < 0 || tagEndOpen > docTextCase.length()) { tagEndOpen = docTextCase.length(); }
+                       String bodyText = jtpSource.getText().substring(tagStartClose, tagEndOpen);
+                       fw.write(bodyText, 0, bodyText.length());
+                       fw.flush();
+                       fw.close();
+               }
+               refreshOnUpdate();
+       }
+
+       /** Method for saving text as an RTF document
+         */
+       private void writeOutRTF(StyledDocument doc)
+       throws IOException, BadLocationException
+       {
+               File whatFile = getFileFromChooser(".", JFileChooser.SAVE_DIALOG, extsRTF, Translatrix.getTranslationString("FiletypeRTF"));
+               if(whatFile != null)
+               {
+                       FileOutputStream fos = new FileOutputStream(whatFile);
+                       RTFEditorKit rtfKit = new RTFEditorKit();
+                       rtfKit.write(fos, doc, 0, doc.getLength());
+                       fos.flush();
+                       fos.close();
+               }
+               refreshOnUpdate();
+       }
+
+       /** Method for saving text as a Base64 encoded document
+         */
+       private void writeOutBase64(String text)
+       throws IOException, BadLocationException
+       {
+               File whatFile = getFileFromChooser(".", JFileChooser.SAVE_DIALOG, extsB64, Translatrix.getTranslationString("FiletypeB64"));
+               if(whatFile != null)
+               {
+                       String base64text = Base64Codec.encode(text);
+                       FileWriter fw = new FileWriter(whatFile);
+                       fw.write(base64text, 0, base64text.length());
+                       fw.flush();
+                       fw.close();
+               }
+               refreshOnUpdate();
+       }
+
+       /** Method to invoke loading HTML into the app
+         */
+       private void openDocument(File whatFile)
+       throws IOException, BadLocationException
+       {
+               if(whatFile == null)
+               {
+                       whatFile = getFileFromChooser(".", JFileChooser.OPEN_DIALOG, extsHTML, Translatrix.getTranslationString("FiletypeHTML"));
+               }
+               if(whatFile != null)
+               {
+                       try
+                       {
+                               loadDocument(whatFile, null);
+                       }
+                       catch(ChangedCharSetException ccse)
+                       {
+                               String charsetType = ccse.getCharSetSpec().toLowerCase();
+                               int pos = charsetType.indexOf("charset");
+                               if(pos == -1)
+                               {
+                                       throw ccse;
+                               }
+                               while(pos < charsetType.length() && charsetType.charAt(pos) != '=')
+                               {
+                                       pos++;
+                               }
+                               pos++; // Places file cursor past the equals sign (=)
+                               String whatEncoding = charsetType.substring(pos).trim();
+                               loadDocument(whatFile, whatEncoding);
+                       }
+               }
+               refreshOnUpdate();
+       }
+
+       /** Method for loading HTML document into the app, including document encoding setting
+         */
+       private void loadDocument(File whatFile, String whatEncoding)
+       throws IOException, BadLocationException
+       {
+               Reader r = null;
+               htmlDoc = (ExtendedHTMLDocument)(htmlKit.createDefaultDocument());
+               try
+               {
+                       if(whatEncoding == null)
+                       {
+                               r = new InputStreamReader(new FileInputStream(whatFile));
+                       }
+                       else
+                       {
+                               r = new InputStreamReader(new FileInputStream(whatFile), whatEncoding);
+                               htmlDoc.putProperty("IgnoreCharsetDirective", new Boolean(true));
+                       }
+                       htmlKit.read(r, htmlDoc, 0);
+                       r.close();
+                       registerDocument(htmlDoc);
+                       jtpSource.setText(jtpMain.getText());
+                       currentFile = whatFile;
+                       updateTitle();
+               }
+               finally
+               {
+                       if(r != null)
+                       {
+                               r.close();
+                       }
+               }
+       }
+
+       /** Method for loading a Base64 encoded document
+         */
+       private void openDocumentBase64(File whatFile)
+       throws IOException, BadLocationException
+       {
+               if(whatFile == null)
+               {
+                       whatFile = getFileFromChooser(".", JFileChooser.OPEN_DIALOG, extsB64, Translatrix.getTranslationString("FiletypeB64"));
+               }
+               if(whatFile != null)
+               {
+                       FileReader fr = new FileReader(whatFile);
+                       int nextChar = 0;
+                       StringBuffer encodedText = new StringBuffer();
+                       try
+                       {
+                               while((nextChar = fr.read()) != -1)
+                               {
+                                       encodedText.append((char)nextChar);
+                               }
+                               fr.close();
+                               jtpSource.setText(Base64Codec.decode(encodedText.toString()));
+                               jtpMain.setText(jtpSource.getText());
+                               registerDocument((ExtendedHTMLDocument)(jtpMain.getDocument()));
+                       }
+                       finally
+                       {
+                               if(fr != null)
+                               {
+                                       fr.close();
+                               }
+                       }
+               }
+       }
+
+       /** Method for loading a Stylesheet into the app
+         */
+       private void openStyleSheet(File fileCSS)
+       throws IOException
+       {
+               if(fileCSS == null)
+               {
+                       fileCSS = getFileFromChooser(".", JFileChooser.OPEN_DIALOG, extsCSS, Translatrix.getTranslationString("FiletypeCSS"));
+               }
+               if(fileCSS != null)
+               {
+                       String currDocText = jtpMain.getText();
+                       htmlDoc = (ExtendedHTMLDocument)(htmlKit.createDefaultDocument());
+                       styleSheet = htmlDoc.getStyleSheet();
+                       URL cssUrl = fileCSS.toURL();
+                       InputStream is = cssUrl.openStream();
+                       BufferedReader br = new BufferedReader(new InputStreamReader(is));
+                       styleSheet.loadRules(br, cssUrl);
+                       br.close();
+                       htmlDoc = new ExtendedHTMLDocument(styleSheet);
+                       registerDocument(htmlDoc);
+                       jtpMain.setText(currDocText);
+                       jtpSource.setText(jtpMain.getText());
+               }
+               refreshOnUpdate();
+       }
+
+       /** Method for serializing the document out to a file
+         */
+       public void serializeOut(HTMLDocument doc)
+       throws IOException
+       {
+               File whatFile = getFileFromChooser(".", JFileChooser.SAVE_DIALOG, extsSer, Translatrix.getTranslationString("FiletypeSer"));
+               if(whatFile != null)
+               {
+                       ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(whatFile));
+                       oos.writeObject(doc);
+                       oos.flush();
+                       oos.close();
+               }
+               refreshOnUpdate();
+       }
+
+       /** Method for reading in a serialized document from a file
+         */
+       public void serializeIn()
+       throws IOException, ClassNotFoundException
+       {
+               File whatFile = getFileFromChooser(".", JFileChooser.OPEN_DIALOG, extsSer, Translatrix.getTranslationString("FiletypeSer"));
+               if(whatFile != null)
+               {
+                       ObjectInputStream ois = new ObjectInputStream(new FileInputStream(whatFile));
+                       htmlDoc = (ExtendedHTMLDocument)(ois.readObject());
+                       ois.close();
+                       registerDocument(htmlDoc);
+                       validate();
+               }
+               refreshOnUpdate();
+       }
+
+       /** Method for obtaining a File for input/output using a JFileChooser dialog
+         */
+       private File getFileFromChooser(String startDir, int dialogType, String[] exts, String desc)
+       {
+               JFileChooser jfileDialog = new JFileChooser(startDir);
+               jfileDialog.setDialogType(dialogType);
+               jfileDialog.setFileFilter(new MutableFilter(exts, desc));
+               int optionSelected = JFileChooser.CANCEL_OPTION;
+               if(dialogType == JFileChooser.OPEN_DIALOG)
+               {
+                       optionSelected = jfileDialog.showOpenDialog(this);
+               }
+               else if(dialogType == JFileChooser.SAVE_DIALOG)
+               {
+                       optionSelected = jfileDialog.showSaveDialog(this);
+               }
+               else // default to an OPEN_DIALOG
+               {
+                       optionSelected = jfileDialog.showOpenDialog(this);
+               }
+               if(optionSelected == JFileChooser.APPROVE_OPTION)
+               {
+                       return jfileDialog.getSelectedFile();
+               }
+               return (File)null;
+       }
+
+       /** Method for obtaining an Image for input using a custom JFileChooser dialog
+         */
+       private File getImageFromChooser(String startDir, String[] exts, String desc)
+       {
+               ImageFileChooser jImageDialog = new ImageFileChooser(startDir);
+               jImageDialog.setDialogType(JFileChooser.CUSTOM_DIALOG);
+               jImageDialog.setFileFilter(new MutableFilter(exts, desc));
+               jImageDialog.setDialogTitle(Translatrix.getTranslationString("ImageDialogTitle"));
+               int optionSelected = JFileChooser.CANCEL_OPTION;
+               optionSelected = jImageDialog.showDialog(this, Translatrix.getTranslationString("Insert"));
+               if(optionSelected == JFileChooser.APPROVE_OPTION)
+               {
+                       return jImageDialog.getSelectedFile();
+               }
+               return (File)null;
+       }
+
+       /** Method for describing the node hierarchy of the document
+         */
+       private void describeDocument(StyledDocument doc)
+       {
+               Element[] elements = doc.getRootElements();
+               for(int i = 0; i < elements.length; i++)
+               {
+                       indent = indentStep;
+                       for(int j = 0; j < indent; j++) { System.out.print(" "); }
+                       System.out.print(elements[i]);
+                       traverseElement(elements[i]);
+                       System.out.println("");
+               }
+       }
+
+       /** Traverses nodes for the describing method
+         */
+       private void traverseElement(Element element)
+       {
+               indent += indentStep;
+               for(int i = 0; i < element.getElementCount(); i++)
+               {
+                       for(int j = 0; j < indent; j++) { System.out.print(" "); }
+                       System.out.print(element.getElement(i));
+                       traverseElement(element.getElement(i));
+               }
+               indent -= indentStep;
+       }
+
+       /** Method to locate a node element by name
+         */
+       private Element locateElementInDocument(StyledDocument doc, String elementName)
+       {
+               Element[] elements = doc.getRootElements();
+               for(int i = 0; i < elements.length; i++)
+               {
+                       if(elements[i].getName().equalsIgnoreCase(elementName))
+                       {
+                               return elements[i];
+                       }
+                       else
+                       {
+                               Element rtnElement = locateChildElementInDocument(elements[i], elementName);
+                               if(rtnElement != null)
+                               {
+                                       return rtnElement;
+                               }
+                       }
+               }
+               return (Element)null;
+       }
+
+       /** Traverses nodes for the locating method
+         */
+       private Element locateChildElementInDocument(Element element, String elementName)
+       {
+               for(int i = 0; i < element.getElementCount(); i++)
+               {
+                       if(element.getElement(i).getName().equalsIgnoreCase(elementName))
+                       {
+                               return element.getElement(i);
+                       }
+               }
+               return (Element)null;
+       }
+
+       /** Convenience method for obtaining the WYSIWYG JTextPane
+         */
+       public JTextPane getTextPane()
+       {
+               return jtpMain;
+       }
+
+       /** Convenience method for obtaining the Source JTextPane
+         */
+       public JTextPane getSourcePane()
+       {
+               return jtpSource;
+       }
+
+       /** Convenience method for obtaining the application as a Frame
+         */
+       public Frame getFrame()
+       {
+               return frameHandler;
+       }
+
+       /** Convenience method for setting the parent Frame
+         */
+       public void setFrame(Frame parentFrame)
+       {
+               frameHandler = parentFrame;
+       }
+
+       /** Convenience method for obtaining the pre-generated menu bar
+         */
+       public JMenuBar getMenuBar()
+       {
+               return jMenuBar;
+       }
+
+       /** Convenience method for obtaining a custom menu bar
+         */
+       public JMenuBar getCustomMenuBar(Vector vcMenus)
+       {
+               jMenuBar = new JMenuBar();
+               for(int i = 0; i < vcMenus.size(); i++)
+               {
+                       String menuToAdd = ((String)(vcMenus.elementAt(i))).toLowerCase();
+                       if(htMenus.containsKey(menuToAdd))
+                       {
+                               jMenuBar.add((JMenu)(htMenus.get(menuToAdd)));
+                       }
+               }
+               return jMenuBar;
+       }
+
+       /** Convenience method for obtaining the pre-generated toolbar
+         */
+       public JToolBar getToolBar(boolean isShowing)
+       {
+               jcbmiViewToolbar.setState(isShowing);
+               return jToolBar;
+       }
+
+       /** Convenience method for obtaining the pre-generated toolbar
+         */
+       public JToolBar getCustomToolBar(Vector vcTools, boolean isShowing)
+       {
+               jcbmiViewToolbar.setState(isShowing);
+               jToolBar = new JToolBar(JToolBar.HORIZONTAL);
+               jToolBar.setFloatable(false);
+               for(int i = 0; i < vcTools.size(); i++)
+               {
+                       String toolToAdd = ((String)(vcTools.elementAt(i))).toLowerCase();
+                       if(toolToAdd.equals(KEY_TOOL_SEP))
+                       {
+                               jToolBar.add(new JToolBar.Separator());
+                       }
+                       else if(htTools.containsKey(toolToAdd))
+                       {
+                               if(htTools.get(toolToAdd) instanceof JButtonNoFocus)
+                               {
+                                       jToolBar.add((JButtonNoFocus)(htTools.get(toolToAdd)));
+                               }
+                               else if(htTools.get(toolToAdd) instanceof JToggleButtonNoFocus)
+                               {
+                                       jToolBar.add((JToggleButtonNoFocus)(htTools.get(toolToAdd)));
+                               }
+                               else if(htTools.get(toolToAdd) instanceof JComboBoxNoFocus)
+                               {
+                                       jToolBar.add((JComboBoxNoFocus)(htTools.get(toolToAdd)));
+                               }
+                               else
+                               {
+                                       jToolBar.add((JComponent)(htTools.get(toolToAdd)));
+                               }
+                       }
+               }
+               return jToolBar;
+       }
+
+       /** Convenience method for obtaining the current file handle
+         */
+       public File getCurrentFile()
+       {
+               return currentFile;
+       }
+
+       /** Convenience method for obtaining the application name
+         */
+       public String getAppName()
+       {
+               return appName;
+       }
+
+       /** Convenience method for obtaining the document text
+         */
+       public String getDocumentText()
+       {
+               return jtpMain.getText();
+       }
+
+       /** Convenience method for obtaining the document text
+         * contained within a tag pair
+         */
+       public String getDocumentSubText(String tagBlock)
+       {
+               return getSubText(tagBlock);
+       }
+
+       /** Method for extracting the text within a tag
+         */
+       private String getSubText(String containingTag)
+       {
+               jtpSource.setText(jtpMain.getText());
+               String docTextCase = jtpSource.getText().toLowerCase();
+               int tagStart       = docTextCase.indexOf("<" + containingTag.toLowerCase());
+               int tagStartClose  = docTextCase.indexOf(">", tagStart) + 1;
+               String closeTag    = "</" + containingTag.toLowerCase() + ">";
+               int tagEndOpen     = docTextCase.indexOf(closeTag);
+               if(tagStartClose < 0) { tagStartClose = 0; }
+               if(tagEndOpen < 0 || tagEndOpen > docTextCase.length()) { tagEndOpen = docTextCase.length(); }
+               return jtpSource.getText().substring(tagStartClose, tagEndOpen);
+       }
+
+       /** Convenience method for obtaining the document text
+               * contained within the BODY tags (a common request)
+         */
+       public String getDocumentBody()
+       {
+               return getSubText("body");
+       }
+
+       /** Convenience method for setting the document text
+         */
+       public void setDocumentText(String sText)
+       {
+               jtpMain.setText(sText);
+               ((HTMLEditorKit)(jtpMain.getEditorKit())).setDefaultCursor(new Cursor(Cursor.TEXT_CURSOR));
+               jtpSource.setText(jtpMain.getText());
+               ((HTMLEditorKit)(jtpSource.getEditorKit())).setDefaultCursor(new Cursor(Cursor.TEXT_CURSOR));
+       }
+
+       /** Convenience method for obtaining the document text
+         */
+       private void updateTitle()
+       {
+               frameHandler.setTitle(appName + (currentFile == null ? "" : " - " + currentFile.getName()));
+       }
+
+       /** Convenience method for clearing out the UndoManager
+         */
+       public void purgeUndos()
+       {
+               if(undoMngr != null)
+               {
+                       undoMngr.discardAllEdits();
+                       undoAction.updateUndoState();
+                       redoAction.updateRedoState();
+               }
+       }
+
+       /** Convenience method for refreshing and displaying changes
+         */
+       public void refreshOnUpdate()
+       {
+               jtpMain.setText(jtpMain.getText());
+               jtpSource.setText(jtpMain.getText());
+               purgeUndos();
+               this.repaint();
+       }
+
+       /** Convenience method for deallocating the app resources
+         */
+       public void dispose()
+       {
+               frameHandler.dispose();
+               System.exit(0);
+       }
+
+       /** Convenience method for fetching icon images from jar file
+         */
+       private ImageIcon getEkitIcon(String iconName)
+       {
+               return new ImageIcon(Toolkit.getDefaultToolkit().getImage(getClass().getResource("icons/" + iconName + "HK.gif")));
+       }
+
+       /** Convenience method for outputting exceptions
+         */
+       private void logException(String internalMessage, Exception e)
+       {
+               System.err.println(internalMessage);
+               e.printStackTrace(System.err);
+       }
+
+       /** Convenience method for toggling source window visibility
+         */
+       private void toggleSourceWindow()
+       {
+               if(!(jspSource.isShowing()))
+               {
+                       jtpSource.setText(jtpMain.getText());
+                       jspltDisplay.setRightComponent(jspSource);
+                       if(exclusiveEdit)
+                       {
+                               jspltDisplay.setDividerLocation(0);
+                               jspltDisplay.setEnabled(false);
+                       }
+                       else
+                       {
+                               jspltDisplay.setDividerLocation(iSplitPos);
+                               jspltDisplay.setEnabled(true);
+                       }
+               }
+               else
+               {
+                       jtpMain.setText(jtpSource.getText());
+                       iSplitPos = jspltDisplay.getDividerLocation();
+                       jspltDisplay.remove(jspSource);
+                       jtpMain.requestFocus();
+               }
+               this.validate();
+               jcbmiViewSource.setSelected(jspSource.isShowing());
+               jtbtnViewSource.setSelected(jspSource.isShowing());
+       }
+
+       /** Searches the specified element for CLASS attribute setting
+         */
+       private String findStyle(Element element)
+       {
+               AttributeSet as = element.getAttributes();
+               if(as == null)
+               {
+                       return null;
+               }
+               Object val = as.getAttribute(HTML.Attribute.CLASS);
+               if(val != null && (val instanceof String))
+               {
+                       return (String)val;
+               }
+               for(Enumeration e = as.getAttributeNames(); e.hasMoreElements();)
+               {
+                       Object key = e.nextElement();
+                       if(key instanceof HTML.Tag)
+                       {
+                               AttributeSet eas = (AttributeSet)(as.getAttribute(key));
+                               if(eas != null)
+                               {
+                                       val = eas.getAttribute(HTML.Attribute.CLASS);
+                                       if(val != null)
+                                       {
+                                               return (String)val;
+                                       }
+                               }
+                       }
+
+               }
+               return null;
+       }
+
+       /** Handles caret tracking and related events, such as displaying the current style
+         * of the text under the caret
+         */
+       private void handleCaretPositionChange(CaretEvent ce)
+       {
+               int caretPos = ce.getDot();
+               Element element = htmlDoc.getCharacterElement(caretPos);
+/*
+---- TAG EXPLICATOR CODE -------------------------------------------
+               javax.swing.text.ElementIterator ei = new javax.swing.text.ElementIterator(htmlDoc);
+               Element ele;
+               while((ele = ei.next()) != null)
+               {
+                       System.out.println("ELEMENT : " + ele.getName());
+               }
+               System.out.println("ELEMENT:" + element.getName());
+               Element elementParent = element.getParentElement();
+               System.out.println("ATTRS:");
+               AttributeSet attribs = elementParent.getAttributes();
+               for(Enumeration eAttrs = attribs.getAttributeNames(); eAttrs.hasMoreElements();)
+               {
+                       System.out.println("  " + eAttrs.nextElement().toString());
+               }
+               while(elementParent != null && !elementParent.getName().equals("body"))
+               {
+                       String parentName = elementParent.getName();
+                       System.out.println("PARENT:" + parentName);
+                       System.out.println("ATTRS:");
+                       attribs = elementParent.getAttributes();
+                       for(Enumeration eAttr = attribs.getAttributeNames(); eAttr.hasMoreElements();)
+                       {
+                               System.out.println("  " + eAttr.nextElement().toString());
+                       }
+                       elementParent = elementParent.getParentElement();
+               }
+---- END -------------------------------------------
+*/
+               if(element == null)
+               {
+                       return;
+               }
+               String style = null;
+               Vector vcStyles = new Vector();
+               while(element != null)
+               {
+                       if(style == null)
+                       {
+                               style = findStyle(element);
+                       }
+                       vcStyles.add(element);
+                       element = element.getParentElement();
+               }
+               int stylefound = -1;
+               if(style != null)
+               {
+                       for(int i = 0; i < jcmbStyleSelector.getItemCount(); i++)
+                       {
+                               String in = (String)(jcmbStyleSelector.getItemAt(i));
+                               if(in.equalsIgnoreCase(style))
+                               {
+                                       stylefound = i;
+                                       break;
+                               }
+                       }
+               }
+               if(stylefound > -1)
+               {
+                       Action ac = jcmbStyleSelector.getAction();
+                       ac.setEnabled(false);
+                       jcmbStyleSelector.setSelectedIndex(stylefound);
+                       ac.setEnabled(true);
+               }
+               else
+               {
+                       jcmbStyleSelector.setSelectedIndex(0);
+               }
+       }
+
+       /** Server-side image handling methods
+         */
+       protected void setServletURL(String url)
+       {
+               ServletURL = url;
+       }
+
+       protected void setImageDir(String sysDir)
+       {
+               ImageDir = sysDir;
+       }
+
+       public void setTreePilotSystemID(String theSystem)
+       {
+               TreePilotSystemID = theSystem;
+       }
+
+       /** Utility methods
+         */
+       public ExtendedHTMLDocument getExtendedHtmlDoc()
+       {
+               return (ExtendedHTMLDocument)htmlDoc;
+       }
+
+       public int getCaretPosition()
+       {
+               return jtpMain.getCaretPosition();
+       }
+
+       public void setCaretPosition(int newPositon)
+       {
+               boolean end = true;
+               do
+               {
+                       end = true;
+                       try
+                       {
+                               jtpMain.setCaretPosition(newPositon);
+                       }
+                       catch (IllegalArgumentException iae)
+                       {
+                               end = false;
+                               newPositon--;
+                       }
+               } while(!end && newPositon >= 0);
+       }
+
+/* Inner Classes --------------------------------------------- */
+
+       /** Class for implementing Undo as an autonomous action
+         */
+       class UndoAction extends AbstractAction
+       {
+               public UndoAction()
+               {
+                       super(Translatrix.getTranslationString("Undo"));
+                       setEnabled(false);
+               }
+
+               public void actionPerformed(ActionEvent e)
+               {
+                       try
+                       {
+                               undoMngr.undo();
+                       }
+                       catch(CannotUndoException ex)
+                       {
+                               ex.printStackTrace();
+                       }
+                       updateUndoState();
+                       redoAction.updateRedoState();
+               }
+
+               protected void updateUndoState()
+               {
+                       if(undoMngr.canUndo())
+                       {
+                               setEnabled(true);
+                               putValue(Action.NAME, undoMngr.getUndoPresentationName());
+                       }
+                       else
+                       {
+                               setEnabled(false);
+                               putValue(Action.NAME, Translatrix.getTranslationString("Undo"));
+                       }
+               }
+       }
+
+       /** Class for implementing Redo as an autonomous action
+         */
+       class RedoAction extends AbstractAction
+       {
+               public RedoAction()
+               {
+                       super(Translatrix.getTranslationString("Redo"));
+                       setEnabled(false);
+               }
+
+               public void actionPerformed(ActionEvent e)
+               {
+                       try
+                       {
+                               undoMngr.redo();
+                       }
+                       catch(CannotUndoException ex)
+                       {
+                               ex.printStackTrace();
+                       }
+                       updateRedoState();
+                       undoAction.updateUndoState();
+               }
+
+               protected void updateRedoState()
+               {
+                       if(undoMngr.canRedo())
+                       {
+                               setEnabled(true);
+                               putValue(Action.NAME, undoMngr.getRedoPresentationName());
+                       }
+                       else
+                       {
+                               setEnabled(false);
+                               putValue(Action.NAME, Translatrix.getTranslationString("Redo"));
+                       }
+               }
+       }
+
+       /** Class for implementing the Undo listener to handle the Undo and Redo actions
+         */
+       class CustomUndoableEditListener implements UndoableEditListener
+       {
+               public void undoableEditHappened(UndoableEditEvent uee)
+               {
+                       undoMngr.addEdit(uee.getEdit());
+                       undoAction.updateUndoState();
+                       redoAction.updateRedoState();
+               }
+       }
+
+}
diff --git a/ekit/com/hexidec/ekit/EkitCore_Spell.java b/ekit/com/hexidec/ekit/EkitCore_Spell.java
new file mode 100644 (file)
index 0000000..cc31e19
--- /dev/null
@@ -0,0 +1,2879 @@
+/*
+GNU Lesser General Public License
+
+EkitCore - Base Java Swing HTML Editor & Viewer Class (Spellcheck Version)
+Copyright (C) 2000-2003 Howard Kistler
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+package com.hexidec.ekit;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Cursor;
+import java.awt.Dimension;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.Image;
+import java.awt.Insets;
+import java.awt.Toolkit;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Reader;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.MalformedURLException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+import java.util.Vector;
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+import javax.swing.JDialog;
+import javax.swing.JEditorPane;
+import javax.swing.JFileChooser;
+import javax.swing.JFrame;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSplitPane;
+import javax.swing.JTextField;
+import javax.swing.JTextPane;
+import javax.swing.JToggleButton;
+import javax.swing.JToolBar;
+import javax.swing.KeyStroke;
+import javax.swing.event.CaretEvent;
+import javax.swing.event.CaretListener;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import javax.swing.event.UndoableEditEvent;
+import javax.swing.event.UndoableEditListener;
+import javax.swing.filechooser.FileFilter;
+import javax.swing.text.AttributeSet;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.ChangedCharSetException;
+import javax.swing.text.DefaultEditorKit;
+import javax.swing.text.DefaultStyledDocument;
+import javax.swing.text.Document;
+import javax.swing.text.Element;
+import javax.swing.text.PlainDocument;
+import javax.swing.text.Position;
+import javax.swing.text.Style;
+import javax.swing.text.StyleConstants;
+import javax.swing.text.StyledDocument;
+import javax.swing.text.StyledEditorKit;
+import javax.swing.text.StyledEditorKit.FontSizeAction;
+import javax.swing.text.html.HTML;
+import javax.swing.text.html.HTMLDocument;
+import javax.swing.text.html.HTMLEditorKit;
+import javax.swing.text.html.StyleSheet;
+import javax.swing.text.rtf.RTFEditorKit;
+import javax.swing.undo.UndoManager;
+import javax.swing.undo.CannotUndoException;
+
+import com.hexidec.ekit.action.*;
+import com.hexidec.ekit.component.*;
+import com.hexidec.util.Base64Codec;
+import com.hexidec.util.Translatrix;
+
+import  com.swabunga.spell.engine.*;
+import  com.swabunga.spell.event.*;
+import  com.swabunga.spell.swing.*;
+
+/** EkitCore
+  * Main application class for editing and saving HTML in a Java text component
+  *
+  * @author Howard Kistler
+  * @version 0.9g
+  *
+  * REQUIREMENTS
+  * Java 2 (JDK 1.3 or 1.4)
+  * Swing Library
+  */
+
+public class EkitCore extends JPanel implements ActionListener, KeyListener, DocumentListener, SpellCheckListener
+{
+       /* Components */
+       private JSplitPane jspltDisplay;
+       private JTextPane jtpMain;
+       private ExtendedHTMLEditorKit htmlKit;
+       private ExtendedHTMLDocument htmlDoc;
+       private StyleSheet styleSheet;
+       private JTextPane jtpSource;
+       private JScrollPane jspSource;
+       private JToolBar jToolBar;
+
+       private JCheckBoxMenuItem jcbmiViewToolbar;
+       private JCheckBoxMenuItem jcbmiViewSource;
+
+       private JButtonNoFocus jbtnNewHTML;
+       private JButtonNoFocus jbtnOpenHTML;
+       private JButtonNoFocus jbtnSaveHTML;
+       private JButtonNoFocus jbtnCut;
+       private JButtonNoFocus jbtnCopy;
+       private JButtonNoFocus jbtnPaste;
+       private JButtonNoFocus jbtnBold;
+       private JButtonNoFocus jbtnItalic;
+       private JButtonNoFocus jbtnUnderline;
+       private JButtonNoFocus jbtnStrike;
+       private JButtonNoFocus jbtnSuperscript;
+       private JButtonNoFocus jbtnSubscript;
+       private JButtonNoFocus jbtnUList;
+       private JButtonNoFocus jbtnOList;
+       private JButtonNoFocus jbtnClearFormat;
+       private JButtonNoFocus jbtnAnchor;
+       private JToggleButtonNoFocus jtbtnViewSource;
+       private JComboBoxNoFocus jcmbStyleSelector;
+
+       private Frame frameHandler;
+
+       private HTMLUtilities htmlUtilities = new HTMLUtilities(this);
+
+       /* Actions */
+       private StyledEditorKit.BoldAction actionFontBold;
+       private StyledEditorKit.ItalicAction actionFontItalic;
+       private StyledEditorKit.UnderlineAction actionFontUnderline;
+       private FormatAction actionFontStrike;
+       private FormatAction actionFontSuperscript;
+       private FormatAction actionFontSubscript;
+       private ListAutomationAction actionListUnordered;
+       private ListAutomationAction actionListOrdered;
+       private CustomAction actionSelectFont;
+       private CustomAction actionClearFormat;
+       private CustomAction actionInsertAnchor;
+
+       protected UndoManager undoMngr;
+       protected UndoAction undoAction;
+       protected RedoAction redoAction;
+
+       /* Menus */
+       private JMenuBar jMenuBar;
+       private JMenu jMenuFile;
+       private JMenu jMenuEdit;
+       private JMenu jMenuView;
+       private JMenu jMenuFont;
+       private JMenu jMenuFormat;
+       private JMenu jMenuInsert;
+       private JMenu jMenuTable;
+       private JMenu jMenuForms;
+       private JMenu jMenuSearch;
+       private JMenu jMenuTools;
+       private JMenu jMenuHelp;
+       private JMenu jMenuDebug;
+
+       /* Constants */
+       // Menu Keys
+       public static final String KEY_MENU_FILE   = "file";
+       public static final String KEY_MENU_EDIT   = "edit";
+       public static final String KEY_MENU_VIEW   = "view";
+       public static final String KEY_MENU_FONT   = "font";
+       public static final String KEY_MENU_FORMAT = "format";
+       public static final String KEY_MENU_INSERT = "insert";
+       public static final String KEY_MENU_TABLE  = "table";
+       public static final String KEY_MENU_FORMS  = "forms";
+       public static final String KEY_MENU_SEARCH = "search";
+       public static final String KEY_MENU_TOOLS  = "tools";
+       public static final String KEY_MENU_HELP   = "help";
+       public static final String KEY_MENU_DEBUG  = "debug";
+
+       // Tool Keys
+       public static final String KEY_TOOL_SEP       = "separator";
+       public static final String KEY_TOOL_NEW       = "new";
+       public static final String KEY_TOOL_OPEN      = "open";
+       public static final String KEY_TOOL_SAVE      = "save";
+       public static final String KEY_TOOL_CUT       = "cut";
+       public static final String KEY_TOOL_COPY      = "copy";
+       public static final String KEY_TOOL_PASTE     = "paste";
+       public static final String KEY_TOOL_BOLD      = "bold";
+       public static final String KEY_TOOL_ITALIC    = "italic";
+       public static final String KEY_TOOL_UNDERLINE = "underline";
+       public static final String KEY_TOOL_STRIKE    = "strike";
+       public static final String KEY_TOOL_SUPER     = "superscript";
+       public static final String KEY_TOOL_SUB       = "subscript";
+       public static final String KEY_TOOL_ULIST     = "ulist";
+       public static final String KEY_TOOL_OLIST     = "olist";
+       public static final String KEY_TOOL_CLEAR     = "clearformats";
+       public static final String KEY_TOOL_ANCHOR    = "anchor";
+       public static final String KEY_TOOL_SOURCE    = "viewsource";
+       public static final String KEY_TOOL_STYLES    = "styleselect";
+
+       // Menu & Tool Key Arrays
+       private static Hashtable htMenus = new Hashtable();
+       private static Hashtable htTools = new Hashtable();
+
+       private final String appName = "Ekit";
+       private final String menuDialog = "..."; /* text to append to a MenuItem label when menu item opens a dialog */
+
+       private final boolean useFormIndicator = true; /* Creates a highlighted background on a new FORM so that it may be more easily edited */
+       private final String clrFormIndicator = "#cccccc";
+
+       // System Clipboard Settings
+       private java.awt.datatransfer.Clipboard sysClipboard;
+       private SecurityManager secManager;
+
+       /* Variables */
+       private int iSplitPos = 0;
+
+       private boolean exclusiveEdit = true;
+
+       private String lastSearchFindTerm     = null;
+       private String lastSearchReplaceTerm  = null;
+       private boolean lastSearchCaseSetting = false;
+       private boolean lastSearchTopSetting  = false;
+
+       private File currentFile = null;
+
+       private int indent = 0;
+       private final int indentStep = 4;
+
+       // File extensions for MutableFilter
+       private final String[] extsHTML = { "html", "htm", "shtml" };
+       private final String[] extsCSS  = { "css" };
+       private final String[] extsIMG  = { "gif", "jpg", "jpeg", "png" };
+       private final String[] extsRTF  = { "rtf" };
+       private final String[] extsB64  = { "b64" };
+       private final String[] extsSer  = { "ser" };
+
+       /* Spell Checker Settings */
+       private static String dictFile;
+       private SpellChecker spellCheck = null;
+       private JSpellDialog spellDialog;
+
+       /* Servlet Settings */
+       private String ServletURL = null;
+       private String TreePilotSystemID = "";
+       private String ImageDir = "";
+       private static ResourceBundle TreePilotProperties;
+
+       /** Master Constructor
+         * @param sDocument         [String]  A text or HTML document to load in the editor upon startup.
+         * @param sStyleSheet       [String]  A CSS stylesheet to load in the editor upon startup.
+         * @param sRawDocument      [String]  A document encoded as a String to load in the editor upon startup.
+         * @param urlStyleSheet     [URL]     A URL reference to the CSS style sheet.
+         * @param showViewSource    [boolean] Specifies whether or not to show the View Source window on startup.
+         * @param showMenuIcons     [boolean] Specifies whether or not to show icon pictures in menus.
+         * @param editModeExclusive [boolean] Specifies whether or not to use exclusive edit mode (recommended on).
+         * @param sLanguage         [String]  The language portion of the Internationalization Locale to run Ekit in.
+         * @param sCountry          [String]  The country portion of the Internationalization Locale to run Ekit in.
+         * @param base64            [boolean] Specifies whether the raw document is Base64 encoded or not.
+         * @param debugMode         [boolean] Specifies whether to show the Debug menu or not.
+         */
+       public EkitCore(String sDocument, String sStyleSheet, String sRawDocument, URL urlStyleSheet, boolean showViewSource, boolean showMenuIcons, boolean editModeExclusive, String sLanguage, String sCountry, boolean base64, boolean debugMode)
+       {
+               super();
+
+               exclusiveEdit = editModeExclusive;
+
+               frameHandler = new Frame();
+
+               // Determine if system clipboard is available
+               secManager = System.getSecurityManager();
+               if(secManager != null)
+               {
+                       try
+                       {
+                               secManager.checkSystemClipboardAccess();
+                               sysClipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
+                       }
+                       catch (SecurityException se)
+                       {
+                               sysClipboard = null;
+                       }
+               }
+
+               /* Localize for language */
+               Translatrix.setBundleName("com.hexidec.ekit.LanguageResources");
+               Locale baseLocale = (Locale)null;
+               if(sLanguage != null && sCountry != null)
+               {
+                       baseLocale = new Locale(sLanguage, sCountry);
+               }
+               Translatrix.setLocale(baseLocale);
+
+               /* Load TreePilot properties */
+               try
+               {
+                       TreePilotProperties = ResourceBundle.getBundle("com.hexidec.ekit.TreePilot");
+               }
+               catch(MissingResourceException mre)
+               {
+                       logException("MissingResourceException while loading treepilot file", mre);
+               }
+
+               /* Create the editor kit, document, and stylesheet */
+               jtpMain = new JTextPane();
+               htmlKit = new ExtendedHTMLEditorKit();
+               htmlDoc = (ExtendedHTMLDocument)(htmlKit.createDefaultDocument());
+               styleSheet = htmlDoc.getStyleSheet();
+               htmlKit.setDefaultCursor(new Cursor(Cursor.TEXT_CURSOR));
+
+               /* Set up the text pane */
+               jtpMain.setEditorKit(htmlKit);
+               jtpMain.setDocument(htmlDoc);
+               jtpMain.setMargin(new Insets(4, 4, 4, 4));
+               jtpMain.addKeyListener(this);
+
+               /* Create the source text area */
+               jtpSource = new JTextPane();
+               jtpSource.setBackground(new Color(212, 212, 212));
+               jtpSource.setSelectionColor(new Color(255, 192, 192));
+               jtpSource.setText(jtpMain.getText());
+               jtpSource.getDocument().addDocumentListener(this);
+
+               /* Add CaretListener for tracking caret location events */
+               jtpMain.addCaretListener(new CaretListener()
+               {
+                       public void caretUpdate(CaretEvent ce)
+                       {
+                               handleCaretPositionChange(ce);
+                       }
+               });
+
+               /* Set up the undo features */
+               undoMngr = new UndoManager();
+               undoAction = new UndoAction();
+               redoAction = new RedoAction();
+               jtpMain.getDocument().addUndoableEditListener(new CustomUndoableEditListener());
+
+               /* Insert raw document, if exists */
+               if(sRawDocument != null && sRawDocument.length() > 0)
+               {
+                       if(base64)
+                       {
+                               jtpMain.setText(Base64Codec.decode(sRawDocument));
+                       }
+                       else
+                       {
+                               jtpMain.setText(sRawDocument);
+                       }
+               }
+               jtpMain.setCaretPosition(0);
+               jtpMain.getDocument().addDocumentListener(this);
+
+               /* Import CSS from reference, if exists */
+               if(urlStyleSheet != null)
+               {
+                       try
+                       {
+                               String currDocText = jtpMain.getText();
+                               htmlDoc = (ExtendedHTMLDocument)(htmlKit.createDefaultDocument());
+                               styleSheet = htmlDoc.getStyleSheet();
+                               BufferedReader br = new BufferedReader(new InputStreamReader(urlStyleSheet.openStream()));
+                               styleSheet.loadRules(br, urlStyleSheet);
+                               br.close();
+                               htmlDoc = new ExtendedHTMLDocument(styleSheet);
+                               registerDocument(htmlDoc);
+                               jtpMain.setText(currDocText);
+                               jtpSource.setText(jtpMain.getText());
+                       }
+                       catch(Exception e)
+                       {
+                               e.printStackTrace(System.out);
+                       }
+               }
+
+               /* Preload the specified HTML document, if exists */
+               if(sDocument != null)
+               {
+                       File defHTML = new File(sDocument);
+                       if(defHTML.exists())
+                       {
+                               try
+                               {
+                                       openDocument(defHTML);
+                               }
+                               catch(Exception e)
+                               {
+                                       logException("Exception in preloading HTML document", e);
+                               }
+                       }
+               }
+
+               /* Preload the specified CSS document, if exists */
+               if(sStyleSheet != null)
+               {
+                       File defCSS = new File(sStyleSheet);
+                       if(defCSS.exists())
+                       {
+                               try
+                               {
+                                       openStyleSheet(defCSS);
+                               }
+                               catch(Exception e)
+                               {
+                                       logException("Exception in preloading CSS stylesheet", e);
+                               }
+                       }
+               }
+
+               /* Collect the actions that the JTextPane is naturally aware of */
+               Hashtable actions = new Hashtable();
+               Action[] actionsArray = jtpMain.getActions();
+               for(int i = 0; i < actionsArray.length; i++)
+               {
+                       Action a = actionsArray[i];
+                       actions.put(a.getValue(Action.NAME), a);
+               }
+
+               /* Create shared actions */
+               actionFontBold        = new StyledEditorKit.BoldAction();
+               actionFontItalic      = new StyledEditorKit.ItalicAction();
+               actionFontUnderline   = new StyledEditorKit.UnderlineAction();
+               actionFontStrike      = new FormatAction(this, Translatrix.getTranslationString("FontStrike"), HTML.Tag.STRIKE);
+               actionFontSuperscript = new FormatAction(this, Translatrix.getTranslationString("FontSuperscript"), HTML.Tag.SUP);
+               actionFontSubscript   = new FormatAction(this, Translatrix.getTranslationString("FontSubscript"), HTML.Tag.SUB);
+               actionListUnordered   = new ListAutomationAction(this, Translatrix.getTranslationString("ListUnordered"), HTML.Tag.UL);
+               actionListOrdered     = new ListAutomationAction(this, Translatrix.getTranslationString("ListOrdered"), HTML.Tag.OL);
+               Hashtable customAttr = new Hashtable();
+               customAttr.put("face","");
+               actionSelectFont      = new CustomAction(this, Translatrix.getTranslationString("FontSelect") + menuDialog, HTML.Tag.FONT, customAttr);
+               actionClearFormat     = new CustomAction(this, Translatrix.getTranslationString("FormatClear"), new HTML.UnknownTag(""));
+               actionInsertAnchor    = new CustomAction(this, Translatrix.getTranslationString("InsertAnchor") + menuDialog, HTML.Tag.A);
+
+               /* Build the menus */
+               /* FILE Menu */
+               jMenuFile              = new JMenu(Translatrix.getTranslationString("File"));
+               htMenus.put(KEY_MENU_FILE, jMenuFile);
+               JMenuItem jmiNew       = new JMenuItem(Translatrix.getTranslationString("NewDocument"));                     jmiNew.setActionCommand("newdoc");        jmiNew.addActionListener(this);      jmiNew.setAccelerator(KeyStroke.getKeyStroke('N', java.awt.Event.CTRL_MASK, false));      if(showMenuIcons) { jmiNew.setIcon(getEkitIcon("New")); }; jMenuFile.add(jmiNew);
+               JMenuItem jmiOpenHTML  = new JMenuItem(Translatrix.getTranslationString("OpenDocument") + menuDialog);       jmiOpenHTML.setActionCommand("openhtml"); jmiOpenHTML.addActionListener(this); jmiOpenHTML.setAccelerator(KeyStroke.getKeyStroke('O', java.awt.Event.CTRL_MASK, false)); if(showMenuIcons) { jmiOpenHTML.setIcon(getEkitIcon("Open")); }; jMenuFile.add(jmiOpenHTML);
+               JMenuItem jmiOpenCSS   = new JMenuItem(Translatrix.getTranslationString("OpenStyle") + menuDialog);          jmiOpenCSS.setActionCommand("opencss");   jmiOpenCSS.addActionListener(this);  jMenuFile.add(jmiOpenCSS);
+               JMenuItem jmiOpenB64   = new JMenuItem(Translatrix.getTranslationString("OpenBase64Document") + menuDialog); jmiOpenB64.setActionCommand("openb64");   jmiOpenB64.addActionListener(this);  jMenuFile.add(jmiOpenB64);
+               jMenuFile.addSeparator();
+               JMenuItem jmiSave      = new JMenuItem(Translatrix.getTranslationString("Save"));                  jmiSave.setActionCommand("save");         jmiSave.addActionListener(this);     jmiSave.setAccelerator(KeyStroke.getKeyStroke('S', java.awt.Event.CTRL_MASK, false)); if(showMenuIcons) { jmiSave.setIcon(getEkitIcon("Save")); }; jMenuFile.add(jmiSave);
+               JMenuItem jmiSaveAs    = new JMenuItem(Translatrix.getTranslationString("SaveAs") + menuDialog);   jmiSaveAs.setActionCommand("saveas");     jmiSaveAs.addActionListener(this);   jMenuFile.add(jmiSaveAs);
+               JMenuItem jmiSaveBody  = new JMenuItem(Translatrix.getTranslationString("SaveBody") + menuDialog); jmiSaveBody.setActionCommand("savebody"); jmiSaveBody.addActionListener(this); jMenuFile.add(jmiSaveBody);
+               JMenuItem jmiSaveRTF   = new JMenuItem(Translatrix.getTranslationString("SaveRTF") + menuDialog);  jmiSaveRTF.setActionCommand("savertf");   jmiSaveRTF.addActionListener(this);  jMenuFile.add(jmiSaveRTF);
+               JMenuItem jmiSaveB64   = new JMenuItem(Translatrix.getTranslationString("SaveB64") + menuDialog);  jmiSaveB64.setActionCommand("saveb64");   jmiSaveB64.addActionListener(this);  jMenuFile.add(jmiSaveB64);
+               jMenuFile.addSeparator();
+               JMenuItem jmiSerialOut = new JMenuItem(Translatrix.getTranslationString("Serialize") + menuDialog);   jmiSerialOut.setActionCommand("serialize");  jmiSerialOut.addActionListener(this); jMenuFile.add(jmiSerialOut);
+               JMenuItem jmiSerialIn  = new JMenuItem(Translatrix.getTranslationString("ReadFromSer") + menuDialog); jmiSerialIn.setActionCommand("readfromser"); jmiSerialIn.addActionListener(this);  jMenuFile.add(jmiSerialIn);
+               jMenuFile.addSeparator();
+               JMenuItem jmiExit      = new JMenuItem(Translatrix.getTranslationString("Exit")); jmiExit.setActionCommand("exit"); jmiExit.addActionListener(this); jMenuFile.add(jmiExit);
+
+               /* EDIT Menu */
+               jMenuEdit            = new JMenu(Translatrix.getTranslationString("Edit"));
+               htMenus.put(KEY_MENU_EDIT, jMenuEdit);
+               if(sysClipboard != null)
+               {
+                       // System Clipboard versions of menu commands
+                       JMenuItem jmiCut     = new JMenuItem(Translatrix.getTranslationString("Cut"));   jmiCut.setActionCommand("textcut");     jmiCut.addActionListener(this);   jmiCut.setAccelerator(KeyStroke.getKeyStroke('X', java.awt.Event.CTRL_MASK, false));   if(showMenuIcons) { jmiCut.setIcon(getEkitIcon("Cut")); }     jMenuEdit.add(jmiCut);
+                       JMenuItem jmiCopy    = new JMenuItem(Translatrix.getTranslationString("Copy"));  jmiCopy.setActionCommand("textcopy");   jmiCopy.addActionListener(this);  jmiCopy.setAccelerator(KeyStroke.getKeyStroke('C', java.awt.Event.CTRL_MASK, false));  if(showMenuIcons) { jmiCopy.setIcon(getEkitIcon("Copy")); }   jMenuEdit.add(jmiCopy);
+                       JMenuItem jmiPaste   = new JMenuItem(Translatrix.getTranslationString("Paste")); jmiPaste.setActionCommand("textpaste"); jmiPaste.addActionListener(this); jmiPaste.setAccelerator(KeyStroke.getKeyStroke('V', java.awt.Event.CTRL_MASK, false)); if(showMenuIcons) { jmiPaste.setIcon(getEkitIcon("Paste")); } jMenuEdit.add(jmiPaste);
+               }
+               else
+               {
+                       // DefaultEditorKit versions of menu commands
+                       JMenuItem jmiCut     = new JMenuItem(new DefaultEditorKit.CutAction());   jmiCut.setText(Translatrix.getTranslationString("Cut"));     jmiCut.setAccelerator(KeyStroke.getKeyStroke('X', java.awt.Event.CTRL_MASK, false));   if(showMenuIcons) { jmiCut.setIcon(getEkitIcon("Cut")); }     jMenuEdit.add(jmiCut);
+                       JMenuItem jmiCopy    = new JMenuItem(new DefaultEditorKit.CopyAction());  jmiCopy.setText(Translatrix.getTranslationString("Copy"));   jmiCopy.setAccelerator(KeyStroke.getKeyStroke('C', java.awt.Event.CTRL_MASK, false));  if(showMenuIcons) { jmiCopy.setIcon(getEkitIcon("Copy")); }   jMenuEdit.add(jmiCopy);
+                       JMenuItem jmiPaste   = new JMenuItem(new DefaultEditorKit.PasteAction()); jmiPaste.setText(Translatrix.getTranslationString("Paste")); jmiPaste.setAccelerator(KeyStroke.getKeyStroke('V', java.awt.Event.CTRL_MASK, false)); if(showMenuIcons) { jmiPaste.setIcon(getEkitIcon("Paste")); } jMenuEdit.add(jmiPaste);
+               }
+               jMenuEdit.addSeparator();
+               JMenuItem jmiUndo    = new JMenuItem(undoAction); jmiUndo.setAccelerator(KeyStroke.getKeyStroke('Z', java.awt.Event.CTRL_MASK, false)); jMenuEdit.add(jmiUndo);
+               JMenuItem jmiRedo    = new JMenuItem(redoAction); jmiRedo.setAccelerator(KeyStroke.getKeyStroke('Y', java.awt.Event.CTRL_MASK, false)); jMenuEdit.add(jmiRedo);
+               jMenuEdit.addSeparator();
+               JMenuItem jmiSelAll  = new JMenuItem((Action)actions.get(DefaultEditorKit.selectAllAction));       jmiSelAll.setText(Translatrix.getTranslationString("SelectAll"));        jmiSelAll.setAccelerator(KeyStroke.getKeyStroke('A', java.awt.Event.CTRL_MASK, false)); jMenuEdit.add(jmiSelAll);
+               JMenuItem jmiSelPara = new JMenuItem((Action)actions.get(DefaultEditorKit.selectParagraphAction)); jmiSelPara.setText(Translatrix.getTranslationString("SelectParagraph")); jMenuEdit.add(jmiSelPara);
+               JMenuItem jmiSelLine = new JMenuItem((Action)actions.get(DefaultEditorKit.selectLineAction));      jmiSelLine.setText(Translatrix.getTranslationString("SelectLine"));      jMenuEdit.add(jmiSelLine);
+               JMenuItem jmiSelWord = new JMenuItem((Action)actions.get(DefaultEditorKit.selectWordAction));      jmiSelWord.setText(Translatrix.getTranslationString("SelectWord"));      jMenuEdit.add(jmiSelWord);
+
+               /* VIEW Menu */
+               jMenuView        = new JMenu(Translatrix.getTranslationString("View"));
+               htMenus.put(KEY_MENU_VIEW, jMenuView);
+               jcbmiViewToolbar = new JCheckBoxMenuItem(Translatrix.getTranslationString("ViewToolbar"), false); jcbmiViewToolbar.setActionCommand("toggletoolbar"); jcbmiViewToolbar.addActionListener(this); jMenuView.add(jcbmiViewToolbar);
+               jcbmiViewSource  = new JCheckBoxMenuItem(Translatrix.getTranslationString("ViewSource"), false);  jcbmiViewSource.setActionCommand("viewsource");     jcbmiViewSource.addActionListener(this);  jMenuView.add(jcbmiViewSource);
+
+               /* FONT Menu */
+               jMenuFont              = new JMenu(Translatrix.getTranslationString("Font"));
+               htMenus.put(KEY_MENU_FONT, jMenuFont);
+               JMenuItem jmiBold      = new JMenuItem(actionFontBold);      jmiBold.setText(Translatrix.getTranslationString("FontBold"));           jmiBold.setAccelerator(KeyStroke.getKeyStroke('B', java.awt.Event.CTRL_MASK, false));      if(showMenuIcons) { jmiBold.setIcon(getEkitIcon("Bold")); }           jMenuFont.add(jmiBold);
+               JMenuItem jmiItalic    = new JMenuItem(actionFontItalic);    jmiItalic.setText(Translatrix.getTranslationString("FontItalic"));       jmiItalic.setAccelerator(KeyStroke.getKeyStroke('I', java.awt.Event.CTRL_MASK, false));    if(showMenuIcons) { jmiItalic.setIcon(getEkitIcon("Italic")); }       jMenuFont.add(jmiItalic);
+               JMenuItem jmiUnderline = new JMenuItem(actionFontUnderline); jmiUnderline.setText(Translatrix.getTranslationString("FontUnderline")); jmiUnderline.setAccelerator(KeyStroke.getKeyStroke('U', java.awt.Event.CTRL_MASK, false)); if(showMenuIcons) { jmiUnderline.setIcon(getEkitIcon("Underline")); } jMenuFont.add(jmiUnderline);
+               JMenuItem jmiStrike    = new JMenuItem(actionFontStrike);    jmiStrike.setText(Translatrix.getTranslationString("FontStrike"));                                                                                                  if(showMenuIcons) { jmiStrike.setIcon(getEkitIcon("Strike")); }       jMenuFont.add(jmiStrike);
+               jMenuFont.addSeparator();
+               jMenuFont.add(new JMenuItem(new FormatAction(this, Translatrix.getTranslationString("FormatBig"), HTML.Tag.BIG)));
+               jMenuFont.add(new JMenuItem(new FormatAction(this, Translatrix.getTranslationString("FormatSmall"), HTML.Tag.SMALL)));
+               JMenu jMenuFontSize = new JMenu(Translatrix.getTranslationString("FontSize"));
+                       String fontSizeKey = "size";
+                       customAttr = new Hashtable(); customAttr.put(fontSizeKey,"1");
+                       jMenuFontSize.add(new JMenuItem(new CustomAction(this, Translatrix.getTranslationString("FontSize1"), HTML.Tag.FONT, customAttr)));
+                       customAttr = new Hashtable(); customAttr.put(fontSizeKey,"2");
+                       jMenuFontSize.add(new JMenuItem(new CustomAction(this, Translatrix.getTranslationString("FontSize2"), HTML.Tag.FONT, customAttr)));
+                       customAttr = new Hashtable(); customAttr.put(fontSizeKey,"3");
+                       jMenuFontSize.add(new JMenuItem(new CustomAction(this, Translatrix.getTranslationString("FontSize3"), HTML.Tag.FONT, customAttr)));
+                       customAttr = new Hashtable(); customAttr.put(fontSizeKey,"4");
+                       jMenuFontSize.add(new JMenuItem(new CustomAction(this, Translatrix.getTranslationString("FontSize4"), HTML.Tag.FONT, customAttr)));
+                       customAttr = new Hashtable(); customAttr.put(fontSizeKey,"5");
+                       jMenuFontSize.add(new JMenuItem(new CustomAction(this, Translatrix.getTranslationString("FontSize5"), HTML.Tag.FONT, customAttr)));
+                       customAttr = new Hashtable(); customAttr.put(fontSizeKey,"6");
+                       jMenuFontSize.add(new JMenuItem(new CustomAction(this, Translatrix.getTranslationString("FontSize6"), HTML.Tag.FONT, customAttr)));
+                       customAttr = new Hashtable(); customAttr.put(fontSizeKey,"7");
+                       jMenuFontSize.add(new JMenuItem(new CustomAction(this, Translatrix.getTranslationString("FontSize7"), HTML.Tag.FONT, customAttr)));
+               jMenuFont.add(jMenuFontSize);
+               jMenuFont.addSeparator();
+               JMenuItem jmiSupscript = new JMenuItem(actionFontSuperscript); if(showMenuIcons) { jmiSupscript.setIcon(getEkitIcon("Super")); } jMenuFont.add(jmiSupscript);
+               JMenuItem jmiSubscript = new JMenuItem(actionFontSubscript);   if(showMenuIcons) { jmiSubscript.setIcon(getEkitIcon("Sub")); }   jMenuFont.add(jmiSubscript);
+               jMenuFont.addSeparator();
+               JMenuItem jmiSerif      = new JMenuItem((Action)actions.get("font-family-Serif"));      jmiSerif.setText(Translatrix.getTranslationString("FontSerif"));           jMenuFont.add(jmiSerif);
+               JMenuItem jmiSansSerif  = new JMenuItem((Action)actions.get("font-family-SansSerif"));  jmiSansSerif.setText(Translatrix.getTranslationString("FontSansserif"));   jMenuFont.add(jmiSansSerif);
+               JMenuItem jmiMonospaced = new JMenuItem((Action)actions.get("font-family-Monospaced")); jmiMonospaced.setText(Translatrix.getTranslationString("FontMonospaced")); jMenuFont.add(jmiMonospaced);
+               JMenuItem jmiSelectFont = new JMenuItem(actionSelectFont);                                                                                                         jMenuFont.add(jmiSelectFont);
+               jMenuFont.addSeparator();
+               JMenu jMenuFontColor = new JMenu(Translatrix.getTranslationString("Color"));
+                       customAttr = new Hashtable(); customAttr.put("color","black");
+                       jMenuFontColor.add(new JMenuItem(new CustomAction(this, Translatrix.getTranslationString("CustomColor") + menuDialog, HTML.Tag.FONT, customAttr)));
+                       jMenuFontColor.add(new JMenuItem(new StyledEditorKit.ForegroundAction(Translatrix.getTranslationString("ColorAqua"),    new Color(  0,255,255))));
+                       jMenuFontColor.add(new JMenuItem(new StyledEditorKit.ForegroundAction(Translatrix.getTranslationString("ColorBlack"),   new Color(  0,  0,  0))));
+                       jMenuFontColor.add(new JMenuItem(new StyledEditorKit.ForegroundAction(Translatrix.getTranslationString("ColorBlue"),    new Color(  0,  0,255))));
+                       jMenuFontColor.add(new JMenuItem(new StyledEditorKit.ForegroundAction(Translatrix.getTranslationString("ColorFuschia"), new Color(255,  0,255))));
+                       jMenuFontColor.add(new JMenuItem(new StyledEditorKit.ForegroundAction(Translatrix.getTranslationString("ColorGray"),    new Color(128,128,128))));
+                       jMenuFontColor.add(new JMenuItem(new StyledEditorKit.ForegroundAction(Translatrix.getTranslationString("ColorGreen"),   new Color(  0,128,  0))));
+                       jMenuFontColor.add(new JMenuItem(new StyledEditorKit.ForegroundAction(Translatrix.getTranslationString("ColorLime"),    new Color(  0,255,  0))));
+                       jMenuFontColor.add(new JMenuItem(new StyledEditorKit.ForegroundAction(Translatrix.getTranslationString("ColorMaroon"),  new Color(128,  0,  0))));
+                       jMenuFontColor.add(new JMenuItem(new StyledEditorKit.ForegroundAction(Translatrix.getTranslationString("ColorNavy"),    new Color(  0,  0,128))));
+                       jMenuFontColor.add(new JMenuItem(new StyledEditorKit.ForegroundAction(Translatrix.getTranslationString("ColorOlive"),   new Color(128,128,  0))));
+                       jMenuFontColor.add(new JMenuItem(new StyledEditorKit.ForegroundAction(Translatrix.getTranslationString("ColorPurple"),  new Color(128,  0,128))));
+                       jMenuFontColor.add(new JMenuItem(new StyledEditorKit.ForegroundAction(Translatrix.getTranslationString("ColorRed"),     new Color(255,  0,  0))));
+                       jMenuFontColor.add(new JMenuItem(new StyledEditorKit.ForegroundAction(Translatrix.getTranslationString("ColorSilver"),  new Color(192,192,192))));
+                       jMenuFontColor.add(new JMenuItem(new StyledEditorKit.ForegroundAction(Translatrix.getTranslationString("ColorTeal"),    new Color(  0,128,128))));
+                       jMenuFontColor.add(new JMenuItem(new StyledEditorKit.ForegroundAction(Translatrix.getTranslationString("ColorWhite"),   new Color(255,255,255))));
+                       jMenuFontColor.add(new JMenuItem(new StyledEditorKit.ForegroundAction(Translatrix.getTranslationString("ColorYellow"),  new Color(255,255,  0))));
+               jMenuFont.add(jMenuFontColor);
+
+               /* FORMAT Menu */
+               jMenuFormat            = new JMenu(Translatrix.getTranslationString("Format"));
+               htMenus.put(KEY_MENU_FORMAT, jMenuFormat);
+               JMenu jMenuFormatAlign = new JMenu(Translatrix.getTranslationString("Align"));
+                       jMenuFormatAlign.add(new JMenuItem(new StyledEditorKit.AlignmentAction(Translatrix.getTranslationString("AlignLeft"), StyleConstants.ALIGN_LEFT)));
+                       jMenuFormatAlign.add(new JMenuItem(new StyledEditorKit.AlignmentAction(Translatrix.getTranslationString("AlignCenter"), StyleConstants.ALIGN_CENTER)));
+                       jMenuFormatAlign.add(new JMenuItem(new StyledEditorKit.AlignmentAction(Translatrix.getTranslationString("AlignRight"), StyleConstants.ALIGN_RIGHT)));
+                       jMenuFormatAlign.add(new JMenuItem(new StyledEditorKit.AlignmentAction(Translatrix.getTranslationString("AlignJustified"), StyleConstants.ALIGN_JUSTIFIED)));
+               jMenuFormat.add(jMenuFormatAlign);
+               jMenuFormat.addSeparator();
+               JMenu jMenuFormatHeading = new JMenu(Translatrix.getTranslationString("Heading"));
+                       jMenuFormatHeading.add(new JMenuItem(new FormatAction(this, Translatrix.getTranslationString("Heading1"), HTML.Tag.H1)));
+                       jMenuFormatHeading.add(new JMenuItem(new FormatAction(this, Translatrix.getTranslationString("Heading2"), HTML.Tag.H2)));
+                       jMenuFormatHeading.add(new JMenuItem(new FormatAction(this, Translatrix.getTranslationString("Heading3"), HTML.Tag.H3)));
+                       jMenuFormatHeading.add(new JMenuItem(new FormatAction(this, Translatrix.getTranslationString("Heading4"), HTML.Tag.H4)));
+                       jMenuFormatHeading.add(new JMenuItem(new FormatAction(this, Translatrix.getTranslationString("Heading5"), HTML.Tag.H5)));
+                       jMenuFormatHeading.add(new JMenuItem(new FormatAction(this, Translatrix.getTranslationString("Heading6"), HTML.Tag.H6)));
+               jMenuFormat.add(jMenuFormatHeading);
+               jMenuFormat.addSeparator();
+               JMenuItem jmiUList = new JMenuItem(actionListUnordered); if(showMenuIcons) { jmiUList.setIcon(getEkitIcon("UList")); } jMenuFormat.add(jmiUList);
+               JMenuItem jmiOList = new JMenuItem(actionListOrdered);   if(showMenuIcons) { jmiOList.setIcon(getEkitIcon("OList")); } jMenuFormat.add(jmiOList);
+               jMenuFormat.add(new JMenuItem(new FormatAction(this, Translatrix.getTranslationString("ListItem"), HTML.Tag.LI)));
+               jMenuFormat.addSeparator();
+               jMenuFormat.add(new JMenuItem(new FormatAction(this, Translatrix.getTranslationString("FormatBlockquote"), HTML.Tag.BLOCKQUOTE)));
+               jMenuFormat.add(new JMenuItem(new FormatAction(this, Translatrix.getTranslationString("FormatPre"), HTML.Tag.PRE)));
+               jMenuFormat.add(new JMenuItem(new FormatAction(this, Translatrix.getTranslationString("FormatStrong"), HTML.Tag.STRONG)));
+               jMenuFormat.add(new JMenuItem(new FormatAction(this, Translatrix.getTranslationString("FormatEmphasis"), HTML.Tag.EM)));
+               jMenuFormat.add(new JMenuItem(new FormatAction(this, Translatrix.getTranslationString("FormatTT"), HTML.Tag.TT)));
+               jMenuFormat.add(new JMenuItem(new FormatAction(this, Translatrix.getTranslationString("FormatSpan"), HTML.Tag.SPAN)));
+               jMenuFormat.addSeparator();
+               JMenuItem jmiClearStyles = new JMenuItem(actionClearFormat); if(showMenuIcons) { jmiClearStyles.setIcon(getEkitIcon("ClearFormat")); }; jMenuFormat.add(jmiClearStyles);
+
+               /* INSERT Menu */
+               jMenuInsert              = new JMenu(Translatrix.getTranslationString("Insert"));
+               htMenus.put(KEY_MENU_INSERT, jMenuInsert);
+               jMenuInsert.add(new JMenuItem(actionInsertAnchor));
+               JMenuItem jmiBreak       = new JMenuItem(Translatrix.getTranslationString("InsertBreak"));                    jmiBreak.setActionCommand("insertbreak"); jmiBreak.addActionListener(this); jmiBreak.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, java.awt.Event.SHIFT_MASK, false)); jMenuInsert.add(jmiBreak);
+               JMenuItem jmiNBSP        = new JMenuItem(Translatrix.getTranslationString("InsertNBSP"));                     jmiNBSP.setActionCommand("insertnbsp");   jmiNBSP.addActionListener(this);  jMenuInsert.add(jmiNBSP);
+               JMenuItem jmiHRule       = new JMenuItem((Action)actions.get("InsertHR"));                                    jmiHRule.setText(Translatrix.getTranslationString("InsertHorizontalRule")); jMenuInsert.add(jmiHRule);
+               jMenuInsert.addSeparator();
+               JMenuItem jmiImageLocal  = new JMenuItem(Translatrix.getTranslationString("InsertLocalImage") + menuDialog);  jmiImageLocal.setActionCommand("insertlocalimage"); jmiImageLocal.addActionListener(this); jMenuInsert.add(jmiImageLocal);
+               JMenuItem jmiImageServer = new JMenuItem(Translatrix.getTranslationString("InsertServerImage") + menuDialog); jmiImageServer.setActionCommand("insertserverimage"); jmiImageServer.addActionListener(this); jMenuInsert.add(jmiImageServer);
+
+               /* TABLE Menu */
+               jMenuTable              = new JMenu(Translatrix.getTranslationString("Table"));
+               htMenus.put(KEY_MENU_TABLE, jMenuTable);
+               JMenuItem jmiTable       = new JMenuItem(Translatrix.getTranslationString("InsertTable") + menuDialog); jmiTable.setActionCommand("inserttable");             jmiTable.addActionListener(this);       jMenuTable.add(jmiTable);
+               jMenuTable.addSeparator();
+               JMenuItem jmiTableRow    = new JMenuItem(Translatrix.getTranslationString("InsertTableRow"));           jmiTableRow.setActionCommand("inserttablerow");       jmiTableRow.addActionListener(this);    jMenuTable.add(jmiTableRow);
+               JMenuItem jmiTableCol    = new JMenuItem(Translatrix.getTranslationString("InsertTableColumn"));        jmiTableCol.setActionCommand("inserttablecolumn");    jmiTableCol.addActionListener(this);    jMenuTable.add(jmiTableCol);
+               jMenuTable.addSeparator();
+               JMenuItem jmiTableRowDel = new JMenuItem(Translatrix.getTranslationString("DeleteTableRow"));           jmiTableRowDel.setActionCommand("deletetablerow");    jmiTableRowDel.addActionListener(this); jMenuTable.add(jmiTableRowDel);
+               JMenuItem jmiTableColDel = new JMenuItem(Translatrix.getTranslationString("DeleteTableColumn"));        jmiTableColDel.setActionCommand("deletetablecolumn"); jmiTableColDel.addActionListener(this); jMenuTable.add(jmiTableColDel);
+
+               /* FORMS Menu */
+               jMenuForms                    = new JMenu(Translatrix.getTranslationString("Forms"));
+               htMenus.put(KEY_MENU_FORMS, jMenuForms);
+               JMenuItem jmiFormInsertForm   = new JMenuItem(Translatrix.getTranslationString("FormInsertForm")); jmiFormInsertForm.setActionCommand("insertform");     jmiFormInsertForm.addActionListener(this); jMenuForms.add(jmiFormInsertForm);
+               jMenuForms.addSeparator();
+               JMenuItem jmiFormTextfield    = new JMenuItem(Translatrix.getTranslationString("FormTextfield"));  jmiFormTextfield.setActionCommand("inserttextfield"); jmiFormTextfield.addActionListener(this);  jMenuForms.add(jmiFormTextfield);
+               JMenuItem jmiFormTextarea     = new JMenuItem(Translatrix.getTranslationString("FormTextarea"));   jmiFormTextarea.setActionCommand("inserttextarea");   jmiFormTextarea.addActionListener(this);   jMenuForms.add(jmiFormTextarea);
+               JMenuItem jmiFormCheckbox     = new JMenuItem(Translatrix.getTranslationString("FormCheckbox"));   jmiFormCheckbox.setActionCommand("insertcheckbox");   jmiFormCheckbox.addActionListener(this);   jMenuForms.add(jmiFormCheckbox);
+               JMenuItem jmiFormRadio        = new JMenuItem(Translatrix.getTranslationString("FormRadio"));      jmiFormRadio.setActionCommand("insertradiobutton");   jmiFormRadio.addActionListener(this);      jMenuForms.add(jmiFormRadio);
+               JMenuItem jmiFormPassword     = new JMenuItem(Translatrix.getTranslationString("FormPassword"));   jmiFormPassword.setActionCommand("insertpassword");   jmiFormPassword.addActionListener(this);   jMenuForms.add(jmiFormPassword);
+               jMenuForms.addSeparator();
+               JMenuItem jmiFormButton       = new JMenuItem(Translatrix.getTranslationString("FormButton"));       jmiFormButton.setActionCommand("insertbutton");             jmiFormButton.addActionListener(this);       jMenuForms.add(jmiFormButton);
+               JMenuItem jmiFormButtonSubmit = new JMenuItem(Translatrix.getTranslationString("FormButtonSubmit")); jmiFormButtonSubmit.setActionCommand("insertbuttonsubmit"); jmiFormButtonSubmit.addActionListener(this); jMenuForms.add(jmiFormButtonSubmit);
+               JMenuItem jmiFormButtonReset  = new JMenuItem(Translatrix.getTranslationString("FormButtonReset"));  jmiFormButtonReset.setActionCommand("insertbuttonreset");   jmiFormButtonReset.addActionListener(this);  jMenuForms.add(jmiFormButtonReset);
+
+               /* SEARCH Menu */
+               jMenuSearch            = new JMenu(Translatrix.getTranslationString("Search"));
+               htMenus.put(KEY_MENU_SEARCH, jMenuSearch);
+               JMenuItem jmiFind      = new JMenuItem(Translatrix.getTranslationString("SearchFind"));      jmiFind.setActionCommand("find");           jmiFind.addActionListener(this);      jmiFind.setAccelerator(KeyStroke.getKeyStroke('F', java.awt.Event.CTRL_MASK, false));      jMenuSearch.add(jmiFind);
+               JMenuItem jmiFindAgain = new JMenuItem(Translatrix.getTranslationString("SearchFindAgain")); jmiFindAgain.setActionCommand("findagain"); jmiFindAgain.addActionListener(this); jmiFindAgain.setAccelerator(KeyStroke.getKeyStroke('G', java.awt.Event.CTRL_MASK, false)); jMenuSearch.add(jmiFindAgain);
+               JMenuItem jmiReplace   = new JMenuItem(Translatrix.getTranslationString("SearchReplace"));   jmiReplace.setActionCommand("replace");     jmiReplace.addActionListener(this);   jmiReplace.setAccelerator(KeyStroke.getKeyStroke('R', java.awt.Event.CTRL_MASK, false));   jMenuSearch.add(jmiReplace);
+
+               /* TOOLS Menu */
+               jMenuTools = new JMenu(Translatrix.getTranslationString("Tools"));
+               htMenus.put(KEY_MENU_TOOLS, jMenuTools);
+               JMenuItem jmiSpellcheck = new JMenuItem(Translatrix.getTranslationString("ToolSpellcheck")); jmiSpellcheck.setActionCommand("spellcheck"); jmiSpellcheck.addActionListener(this); jMenuTools.add(jmiSpellcheck);
+
+               /* HELP Menu */
+               jMenuHelp = new JMenu(Translatrix.getTranslationString("Help"));
+               htMenus.put(KEY_MENU_HELP, jMenuHelp);
+               JMenuItem jmiAbout = new JMenuItem(Translatrix.getTranslationString("About")); jmiAbout.setActionCommand("helpabout"); jmiAbout.addActionListener(this); jMenuHelp.add(jmiAbout);
+
+               /* DEBUG Menu */
+               jMenuDebug           = new JMenu(Translatrix.getTranslationString("Debug"));
+               htMenus.put(KEY_MENU_DEBUG, jMenuDebug);
+               JMenuItem jmiDesc    = new JMenuItem(Translatrix.getTranslationString("DescribeDoc")); jmiDesc.setActionCommand("describe");       jmiDesc.addActionListener(this);    jMenuDebug.add(jmiDesc);
+               JMenuItem jmiDescCSS = new JMenuItem(Translatrix.getTranslationString("DescribeCSS")); jmiDescCSS.setActionCommand("describecss"); jmiDescCSS.addActionListener(this); jMenuDebug.add(jmiDescCSS);
+               JMenuItem jmiTag     = new JMenuItem(Translatrix.getTranslationString("WhatTags"));    jmiTag.setActionCommand("whattags");        jmiTag.addActionListener(this);     jMenuDebug.add(jmiTag);
+
+               /* Create menubar and add menus */
+               jMenuBar = new JMenuBar();
+               jMenuBar.add(jMenuFile);
+               jMenuBar.add(jMenuEdit);
+               jMenuBar.add(jMenuView);
+               jMenuBar.add(jMenuFont);
+               jMenuBar.add(jMenuFormat);
+               jMenuBar.add(jMenuSearch);
+               jMenuBar.add(jMenuInsert);
+               jMenuBar.add(jMenuTable);
+               jMenuBar.add(jMenuForms);
+               jMenuBar.add(jMenuTools);
+               jMenuBar.add(jMenuHelp);
+               if(debugMode)
+               {
+                       jMenuBar.add(jMenuDebug);
+               }
+
+               /* Create the toolbar */
+               jToolBar = new JToolBar(JToolBar.HORIZONTAL);
+               jToolBar.setFloatable(false);
+               jbtnNewHTML     = new JButtonNoFocus(getEkitIcon("New"));  jbtnNewHTML.setToolTipText(Translatrix.getTranslationString("NewDocument"));   jbtnNewHTML.setActionCommand("newdoc");    jbtnNewHTML.addActionListener(this);  jToolBar.add(jbtnNewHTML);  htTools.put(KEY_TOOL_NEW, jbtnNewHTML);
+               jbtnOpenHTML    = new JButtonNoFocus(getEkitIcon("Open")); jbtnOpenHTML.setToolTipText(Translatrix.getTranslationString("OpenDocument")); jbtnOpenHTML.setActionCommand("openhtml"); jbtnOpenHTML.addActionListener(this); jToolBar.add(jbtnOpenHTML); htTools.put(KEY_TOOL_OPEN, jbtnOpenHTML);
+               jbtnSaveHTML    = new JButtonNoFocus(getEkitIcon("Save")); jbtnSaveHTML.setToolTipText(Translatrix.getTranslationString("SaveDocument")); jbtnSaveHTML.setActionCommand("saveas");   jbtnSaveHTML.addActionListener(this); jToolBar.add(jbtnSaveHTML); htTools.put(KEY_TOOL_SAVE, jbtnSaveHTML);
+               jToolBar.add(new JToolBar.Separator());
+               jbtnCut         = new JButtonNoFocus(new DefaultEditorKit.CutAction());   jbtnCut.setIcon(getEkitIcon("Cut"));     jbtnCut.setText(null);   jbtnCut.setToolTipText(Translatrix.getTranslationString("Cut"));     jToolBar.add(jbtnCut);   htTools.put(KEY_TOOL_CUT, jbtnCut);
+               jbtnCopy        = new JButtonNoFocus(new DefaultEditorKit.CopyAction());  jbtnCopy.setIcon(getEkitIcon("Copy"));   jbtnCopy.setText(null);  jbtnCopy.setToolTipText(Translatrix.getTranslationString("Copy"));   jToolBar.add(jbtnCopy);  htTools.put(KEY_TOOL_COPY, jbtnCopy);
+               jbtnPaste       = new JButtonNoFocus(new DefaultEditorKit.PasteAction()); jbtnPaste.setIcon(getEkitIcon("Paste")); jbtnPaste.setText(null); jbtnPaste.setToolTipText(Translatrix.getTranslationString("Paste")); jToolBar.add(jbtnPaste); htTools.put(KEY_TOOL_PASTE, jbtnPaste);
+               jToolBar.add(new JToolBar.Separator());
+               jbtnBold        = new JButtonNoFocus(actionFontBold);        jbtnBold.setIcon(getEkitIcon("Bold"));               jbtnBold.setText(null);        jbtnBold.setToolTipText(Translatrix.getTranslationString("FontBold"));                 jToolBar.add(jbtnBold);        htTools.put(KEY_TOOL_BOLD, jbtnBold);
+               jbtnItalic      = new JButtonNoFocus(actionFontItalic);      jbtnItalic.setIcon(getEkitIcon("Italic"));           jbtnItalic.setText(null);      jbtnItalic.setToolTipText(Translatrix.getTranslationString("FontItalic"));             jToolBar.add(jbtnItalic);      htTools.put(KEY_TOOL_ITALIC, jbtnItalic);
+               jbtnUnderline   = new JButtonNoFocus(actionFontUnderline);   jbtnUnderline.setIcon(getEkitIcon("Underline"));     jbtnUnderline.setText(null);   jbtnUnderline.setToolTipText(Translatrix.getTranslationString("FontUnderline"));       jToolBar.add(jbtnUnderline);   htTools.put(KEY_TOOL_UNDERLINE, jbtnUnderline);
+               jbtnStrike      = new JButtonNoFocus(actionFontStrike);      jbtnStrike.setIcon(getEkitIcon("Strike"));           jbtnStrike.setText(null);      jbtnStrike.setToolTipText(Translatrix.getTranslationString("FontStrike"));             jToolBar.add(jbtnStrike);      htTools.put(KEY_TOOL_STRIKE, jbtnStrike);
+               jbtnSuperscript = new JButtonNoFocus(actionFontSuperscript); jbtnSuperscript.setIcon(getEkitIcon("Super"));       jbtnSuperscript.setText(null); jbtnSuperscript.setToolTipText(Translatrix.getTranslationString("FontSuperscript")); jToolBar.add(jbtnSuperscript);   htTools.put(KEY_TOOL_SUPER, jbtnSuperscript);
+               jbtnSubscript   = new JButtonNoFocus(actionFontSubscript);   jbtnSubscript.setIcon(getEkitIcon("Sub"));           jbtnSubscript.setText(null);   jbtnSubscript.setToolTipText(Translatrix.getTranslationString("FontSubscript"));     jToolBar.add(jbtnSubscript);     htTools.put(KEY_TOOL_SUB, jbtnSubscript);
+               jbtnUList       = new JButtonNoFocus(actionListUnordered);   jbtnUList.setIcon(getEkitIcon("UList"));             jbtnUList.setText(null);       jbtnUList.setToolTipText(Translatrix.getTranslationString("ListUnordered"));           jToolBar.add(jbtnUList);       htTools.put(KEY_TOOL_ULIST, jbtnUList);
+               jbtnOList       = new JButtonNoFocus(actionListOrdered);     jbtnOList.setIcon(getEkitIcon("OList"));             jbtnOList.setText(null);       jbtnOList.setToolTipText(Translatrix.getTranslationString("ListOrdered"));             jToolBar.add(jbtnOList);       htTools.put(KEY_TOOL_OLIST, jbtnOList);
+               jbtnClearFormat = new JButtonNoFocus(actionClearFormat);     jbtnClearFormat.setIcon(getEkitIcon("ClearFormat")); jbtnClearFormat.setText(null); jbtnClearFormat.setToolTipText(Translatrix.getTranslationString("FormatClear"));       jToolBar.add(jbtnClearFormat); htTools.put(KEY_TOOL_CLEAR, jbtnClearFormat);
+               jToolBar.add(new JToolBar.Separator());
+               jbtnAnchor      = new JButtonNoFocus(actionInsertAnchor); jbtnAnchor.setIcon(getEkitIcon("Anchor")); jbtnAnchor.setText(null); jbtnAnchor.setToolTipText(Translatrix.getTranslationString("ToolAnchor")); jToolBar.add(jbtnAnchor); htTools.put(KEY_TOOL_ANCHOR, jbtnAnchor);
+               jToolBar.add(new JToolBar.Separator());
+               jtbtnViewSource = new JToggleButtonNoFocus(getEkitIcon("Source")); jtbtnViewSource.setText(null); jtbtnViewSource.setToolTipText(Translatrix.getTranslationString("ViewSource")); jtbtnViewSource.setActionCommand("viewsource"); jtbtnViewSource.addActionListener(this); jtbtnViewSource.setPreferredSize(jbtnAnchor.getPreferredSize()); jtbtnViewSource.setMinimumSize(jbtnAnchor.getMinimumSize()); jtbtnViewSource.setMaximumSize(jbtnAnchor.getMaximumSize()); jToolBar.add(jtbtnViewSource); htTools.put(KEY_TOOL_SOURCE, jtbtnViewSource);
+               jToolBar.add(new JToolBar.Separator());
+               jcmbStyleSelector = new JComboBoxNoFocus(); jToolBar.add(jcmbStyleSelector); jcmbStyleSelector.setAction(new StylesAction(jcmbStyleSelector)); htTools.put(KEY_TOOL_STYLES, jcmbStyleSelector);
+
+               /* Create the scroll area for the text pane */
+               JScrollPane jspViewport = new JScrollPane(jtpMain);
+               jspViewport.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
+               jspViewport.setPreferredSize(new Dimension(400, 400));
+               jspViewport.setMinimumSize(new Dimension(32, 32));
+
+               /* Create the scroll area for the source viewer */
+               jspSource = new JScrollPane(jtpSource);
+               jspSource.setPreferredSize(new Dimension(400, 100));
+               jspSource.setMinimumSize(new Dimension(32, 32));
+
+               jspltDisplay = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
+               jspltDisplay.setTopComponent(jspViewport);
+               if(showViewSource)
+               {
+                       jspltDisplay.setBottomComponent(jspSource);
+               }
+               else
+               {
+                       jspltDisplay.setBottomComponent(null);
+               }
+
+               iSplitPos = jspltDisplay.getDividerLocation();
+
+               registerDocumentStyles();
+
+               /* Create spell checker */
+               try
+               {
+                       dictFile = Translatrix.getTranslationString("DictionaryFile");
+                       SpellDictionary dictionary = new SpellDictionary(dictFile); // uses my custom loader in SpellDictionary
+                       spellCheck = new SpellChecker(dictionary);
+                       spellCheck.addSpellCheckListener(this);
+               }
+               catch(Exception e)
+               {
+                       e.printStackTrace();
+               }
+               spellDialog = new JSpellDialog(this.getFrame(), Translatrix.getTranslationString("ToolSpellcheckDialog"), true);
+
+               /* Add the components to the app */
+               this.setLayout(new BorderLayout());
+               this.add(jspltDisplay, BorderLayout.CENTER);
+       }
+
+       /** Common Constructor
+         * @param sDocument         [String]  A text or HTML document to load in the editor upon startup.
+         * @param sStyleSheet       [String]  A CSS stylesheet to load in the editor upon startup.
+         * @param showViewSource    [boolean] Specifies whether or not to show the View Source window on startup.
+         * @param showMenuIcons     [boolean] Specifies whether or not to show icon pictures in menus.
+         * @param editModeExclusive [boolean] Specifies whether or not to use exclusive edit mode (recommended on).
+         * @param sLanguage         [String]  The language portion of the Internationalization Locale to run Ekit in.
+         * @param sCountry          [String]  The country portion of the Internationalization Locale to run Ekit in.
+         */
+       public EkitCore(String sDocument, String sStyleSheet, boolean showViewSource, boolean showMenuIcons, boolean editModeExclusive, String sLanguage, String sCountry, boolean base64)
+       {
+               this(sDocument, sStyleSheet, null, null, showViewSource, showMenuIcons, editModeExclusive, sLanguage, sCountry, base64, false);
+       }
+
+       /** Default Language Constructor
+         * @param sDocument         [String]  A text or HTML document to load in the editor upon startup.
+         * @param sStyleSheet       [String]  A CSS stylesheet to load in the editor upon startup.
+         * @param showViewSource    [boolean] Specifies whether or not to show the View Source window on startup.
+         * @param showMenuIcons     [boolean] Specifies whether or not to show icon pictures in menus.
+         * @param editModeExclusive [boolean] Specifies whether or not to use exclusive edit mode (recommended on).
+         */
+       public EkitCore(String sDocument, String sStyleSheet, boolean showViewSource, boolean showMenuIcons, boolean editModeExclusive, boolean base64)
+       {
+               this(sDocument, sStyleSheet, null, null, showViewSource, showMenuIcons, editModeExclusive, null, null, base64, false);
+       }
+
+       /** Raw/Base64 Document & Style Sheet URL Constructor (Ideal for EkitApplet)
+         * @param sRawDocument      [String]  A document encoded as a String to load in the editor upon startup.
+         * @param sRawDocument      [String]  A document encoded as a String to load in the editor upon startup.
+         * @param showViewSource    [boolean] Specifies whether or not to show the View Source window on startup.
+         * @param showMenuIcons     [boolean] Specifies whether or not to show icon pictures in menus.
+         * @param editModeExclusive [boolean] Specifies whether or not to use exclusive edit mode (recommended on).
+         * @param sLanguage         [String]  The language portion of the Internationalization Locale to run Ekit in.
+         * @param sCountry          [String]  The country portion of the Internationalization Locale to run Ekit in.
+         */
+       public EkitCore(String sRawDocument, URL urlStyleSheet, boolean showViewSource, boolean showMenuIcons, boolean editModeExclusive, String sLanguage, String sCountry, boolean base64)
+       {
+               this(null, null, sRawDocument, urlStyleSheet, showViewSource, showMenuIcons, editModeExclusive, sLanguage, sCountry, base64, false);
+       }
+
+       /** Document Constructor
+         * @param sRawDocument      [String]  A document encoded as a String to load in the editor upon startup.
+         * @param showViewSource    [boolean] Specifies whether or not to show the View Source window on startup.
+         * @param showMenuIcons     [boolean] Specifies whether or not to show icon pictures in menus.
+         * @param editModeExclusive [boolean] Specifies whether or not to use exclusive edit mode (recommended on).
+         * @param sLanguage         [String]  The language portion of the Internationalization Locale to run Ekit in.
+         * @param sCountry          [String]  The country portion of the Internationalization Locale to run Ekit in.
+         */
+       public EkitCore(String sRawDocument, boolean showViewSource, boolean showMenuIcons, boolean editModeExclusive, String sLanguage, String sCountry, boolean base64)
+       {
+               this(null, null, sRawDocument, null, showViewSource, showMenuIcons, editModeExclusive, sLanguage, sCountry, base64, false);
+       }
+
+       /** Default Language & Document Constructor
+         * @param sRawDocument      [String]  A document encoded as a String to load in the editor upon startup.
+         * @param showViewSource    [boolean] Specifies whether or not to show the View Source window on startup.
+         * @param showMenuIcons     [boolean] Specifies whether or not to show icon pictures in menus.
+         * @param editModeExclusive [boolean] Specifies whether or not to use exclusive edit mode (recommended on).
+         */
+       public EkitCore(String sRawDocument, boolean showViewSource, boolean showMenuIcons, boolean editModeExclusive, boolean base64)
+       {
+               this(null, null, sRawDocument, null, showViewSource, showMenuIcons, editModeExclusive, null, null, base64, false);
+       }
+
+       /** Flags & Language Constructor
+         * @param showViewSource    [boolean] Specifies whether or not to show the View Source window on startup.
+         * @param showMenuIcons     [boolean] Specifies whether or not to show icon pictures in menus.
+         * @param editModeExclusive [boolean] Specifies whether or not to use exclusive edit mode (recommended on).
+         * @param sLanguage         [String]  The language portion of the Internationalization Locale to run Ekit in.
+         * @param sCountry          [String]  The country portion of the Internationalization Locale to run Ekit in.
+         */
+       public EkitCore(boolean showViewSource, boolean showMenuIcons, boolean editModeExclusive, String sLanguage, String sCountry)
+       {
+               this(null, null, null, null, showViewSource, showMenuIcons, editModeExclusive, sLanguage, sCountry, false, false);
+       }
+
+       /** Flags Constructor
+         * @param showViewSource    [boolean] Specifies whether or not to show the View Source window on startup.
+         * @param showMenuIcons     [boolean] Specifies whether or not to show icon pictures in menus.
+         * @param editModeExclusive [boolean] Specifies whether or not to use exclusive edit mode (recommended on).
+         */
+       public EkitCore(boolean showViewSource, boolean showMenuIcons, boolean editModeExclusive)
+       {
+               this(null, null, null, null, showViewSource, showMenuIcons, editModeExclusive, null, null, false, false);
+       }
+
+       /** Language & Debug Constructor
+         * @param sLanguage [String]  The language portion of the Internationalization Locale to run Ekit in.
+         * @param sCountry  [String]  The country portion of the Internationalization Locale to run Ekit in.
+         * @param debugMode [boolean] Specifies whether to show the Debug menu or not.
+         */
+       public EkitCore(String sLanguage, String sCountry, boolean debugMode)
+       {
+               this(null, null, null, null, false, true, true, sLanguage, sCountry, false, debugMode);
+       }
+
+       /** Language Constructor
+         * @param sLanguage [String]  The language portion of the Internationalization Locale to run Ekit in.
+         * @param sCountry  [String]  The country portion of the Internationalization Locale to run Ekit in.
+         */
+       public EkitCore(String sLanguage, String sCountry)
+       {
+               this(null, null, null, null, false, true, true, sLanguage, sCountry, false, false);
+       }
+
+       /** Debug Constructor
+         * @param debugMode [boolean] Specifies whether to show the Debug menu or not.
+         */
+       public EkitCore(boolean debugMode)
+       {
+               this(null, null, null, null, false, true, true, null, null, false, debugMode);
+       }
+
+       /** Empty Constructor
+         */
+       public EkitCore()
+       {
+               this(null, null, null, null, false, true, true, null, null, false, false);
+       }
+
+       /* ActionListener method */
+       public void actionPerformed(ActionEvent ae)
+       {
+               try
+               {
+                       String command = ae.getActionCommand();
+                       if(command.equals("newdoc"))
+                       {
+                               SimpleInfoDialog sidAsk = new SimpleInfoDialog(this.getFrame(), "", true, Translatrix.getTranslationString("AskNewDocument"), SimpleInfoDialog.QUESTION);
+                               String decision = sidAsk.getDecisionValue();
+                               if(decision.equals(Translatrix.getTranslationString("DialogAccept")))
+                               {
+                                       if(styleSheet != null)
+                                       {
+                                               htmlDoc = new ExtendedHTMLDocument(styleSheet);
+                                       }
+                                       else
+                                       {
+                                               htmlDoc = (ExtendedHTMLDocument)(htmlKit.createDefaultDocument());
+                                       }
+                                       jtpMain.setText("<HTML><BODY></BODY></HTML>");
+                                       jtpSource.setText(jtpMain.getText());
+                                       registerDocument(htmlDoc);
+                                       currentFile = null;
+                                       updateTitle();
+                               }
+                       }
+                       else if(command.equals("openhtml"))
+                       {
+                               openDocument(null);
+                       }
+                       else if(command.equals("opencss"))
+                       {
+                               openStyleSheet(null);
+                       }
+                       else if(command.equals("openb64"))
+                       {
+                               openDocumentBase64(null);
+                       }
+                       else if(command.equals("save"))
+                       {
+                               writeOut((HTMLDocument)(jtpMain.getDocument()), currentFile);
+                               updateTitle();
+                       }
+                       else if(command.equals("saveas"))
+                       {
+                               writeOut((HTMLDocument)(jtpMain.getDocument()), null);
+                       }
+                       else if(command.equals("savebody"))
+                       {
+                               writeOutFragment((HTMLDocument)(jtpMain.getDocument()),"body");
+                       }
+                       else if(command.equals("savertf"))
+                       {
+                               writeOutRTF((StyledDocument)(jtpMain.getStyledDocument()));
+                       }
+                       else if(command.equals("saveb64"))
+                       {
+                               writeOutBase64(jtpSource.getText());
+                       }
+                       else if(command.equals("textcut"))
+                       {
+                               if(jspSource.isShowing() && jtpSource.hasFocus())
+                               {
+                                       jtpSource.cut();
+                               }
+                               else
+                               {
+                                       jtpMain.cut();
+                               }
+                       }
+                       else if(command.equals("textcopy"))
+                       {
+                               if(jspSource.isShowing() && jtpSource.hasFocus())
+                               {
+                                       jtpSource.copy();
+                               }
+                               else
+                               {
+                                       jtpMain.copy();
+                               }
+                       }
+                       else if(command.equals("textpaste"))
+                       {
+                               if(jspSource.isShowing() && jtpSource.hasFocus())
+                               {
+                                       jtpSource.paste();
+                               }
+                               else
+                               {
+                                       jtpMain.paste();
+                               }
+                       }
+                       else if(command.equals("describe"))
+                       {
+                               System.out.println("------------DOCUMENT------------");
+                               System.out.println("Content Type : " + jtpMain.getContentType());
+                               System.out.println("Editor Kit   : " + jtpMain.getEditorKit());
+                               System.out.println("Doc Tree     :");
+                               System.out.println("");
+                               describeDocument(jtpMain.getStyledDocument());
+                               System.out.println("--------------------------------");
+                               System.out.println("");
+                       }
+                       else if(command.equals("describecss"))
+                       {
+                               System.out.println("-----------STYLESHEET-----------");
+                               System.out.println("Stylesheet Rules");
+                               Enumeration rules = styleSheet.getStyleNames();
+                               while(rules.hasMoreElements())
+                               {
+                                       String ruleName = (String)(rules.nextElement());
+                                       Style styleRule = styleSheet.getStyle(ruleName);
+                                       System.out.println(styleRule.toString());
+                               }
+                               System.out.println("--------------------------------");
+                               System.out.println("");
+                       }
+                       else if(command.equals("whattags"))
+                       {
+                               System.out.println("Caret Position : " + jtpMain.getCaretPosition());
+                               AttributeSet attribSet = jtpMain.getCharacterAttributes();
+                               Enumeration attribs = attribSet.getAttributeNames();
+                               System.out.println("Attributes     : ");
+                               while(attribs.hasMoreElements())
+                               {
+                                       String attribName = attribs.nextElement().toString();
+                                       System.out.println("                 " + attribName + " | " + attribSet.getAttribute(attribName));
+                               }
+                       }
+                       else if(command.equals("toggletoolbar"))
+                       {
+                               jToolBar.setVisible(jcbmiViewToolbar.isSelected());
+                       }
+                       else if(command.equals("viewsource"))
+                       {
+                               toggleSourceWindow();
+                       }
+                       else if(command.equals("serialize"))
+                       {
+                               serializeOut((HTMLDocument)(jtpMain.getDocument()));
+                       }
+                       else if(command.equals("readfromser"))
+                       {
+                               serializeIn();
+                       }
+                       else if(command.equals("inserttable"))
+                       {
+                               String[] fieldNames = { "rows", "cols", "border", "cellspacing", "cellpadding", "width" };
+                               String[] fieldTypes = { "text", "text", "text",   "text",        "text",        "text" };
+                               insertTable((Hashtable)null, fieldNames, fieldTypes);
+                       }
+                       else if(command.equals("inserttablerow"))
+                       {
+                               insertTableRow();
+                       }
+                       else if(command.equals("inserttablecolumn"))
+                       {
+                               insertTableColumn();
+                       }
+                       else if(command.equals("deletetablerow"))
+                       {
+                               deleteTableRow();
+                       }
+                       else if(command.equals("deletetablecolumn"))
+                       {
+                               deleteTableColumn();
+                       }
+                       else if(command.equals("insertbreak"))
+                       {
+                               insertBreak();
+                       }
+                       else if(command.equals("insertlocalimage"))
+                       {
+                               insertLocalImage(null);
+                       }
+                       else if(command.equals("insertserverimage"))
+                       {
+                               insertServerImage();
+                       }
+                       else if(command.equals("insertnbsp"))
+                       {
+                               insertNonbreakingSpace();
+                       }
+                       else if(command.equals("insertform"))
+                       {
+                               String[] fieldNames  = { "name", "method",   "enctype" };
+                               String[] fieldTypes  = { "text", "combo",    "text" };
+                               String[] fieldValues = { "",     "POST,GET", "text" };
+                               insertFormElement(HTML.Tag.FORM, "form", (Hashtable)null, fieldNames, fieldTypes, fieldValues, true);
+                       }
+                       else if(command.equals("inserttextfield"))
+                       {
+                               Hashtable htAttribs = new Hashtable();
+                               htAttribs.put("type", "text");
+                               String[] fieldNames = { "name", "value", "size", "maxlength" };
+                               String[] fieldTypes = { "text", "text",  "text", "text" };
+                               insertFormElement(HTML.Tag.INPUT, "input", htAttribs, fieldNames, fieldTypes, false);
+                       }
+                       else if(command.equals("inserttextarea"))
+                       {
+                               String[] fieldNames = { "name", "rows", "cols" };
+                               String[] fieldTypes = { "text", "text", "text" };
+                               insertFormElement(HTML.Tag.TEXTAREA, "textarea", (Hashtable)null, fieldNames, fieldTypes, true);
+                       }
+                       else if(command.equals("insertcheckbox"))
+                       {
+                               Hashtable htAttribs = new Hashtable();
+                               htAttribs.put("type", "checkbox");
+                               String[] fieldNames = { "name", "checked" };
+                               String[] fieldTypes = { "text", "bool" };
+                               insertFormElement(HTML.Tag.INPUT, "input", htAttribs, fieldNames, fieldTypes, false);
+                       }
+                       else if(command.equals("insertradiobutton"))
+                       {
+                               Hashtable htAttribs = new Hashtable();
+                               htAttribs.put("type", "radio");
+                               String[] fieldNames = { "name", "checked" };
+                               String[] fieldTypes = { "text", "bool" };
+                               insertFormElement(HTML.Tag.INPUT, "input", htAttribs, fieldNames, fieldTypes, false);
+                       }
+                       else if(command.equals("insertpassword"))
+                       {
+                               Hashtable htAttribs = new Hashtable();
+                               htAttribs.put("type", "password");
+                               String[] fieldNames = { "name", "value", "size", "maxlength" };
+                               String[] fieldTypes = { "text", "text",  "text", "text" };
+                               insertFormElement(HTML.Tag.INPUT, "input", htAttribs, fieldNames, fieldTypes, false);
+                       }
+                       else if(command.equals("insertbutton"))
+                       {
+                               Hashtable htAttribs = new Hashtable();
+                               htAttribs.put("type", "button");
+                               String[] fieldNames = { "name", "value" };
+                               String[] fieldTypes = { "text", "text" };
+                               insertFormElement(HTML.Tag.INPUT, "input", htAttribs, fieldNames, fieldTypes, false);
+                       }
+                       else if(command.equals("insertbuttonsubmit"))
+                       {
+                               Hashtable htAttribs = new Hashtable();
+                               htAttribs.put("type", "submit");
+                               String[] fieldNames = { "name", "value" };
+                               String[] fieldTypes = { "text", "text" };
+                               insertFormElement(HTML.Tag.INPUT, "input", htAttribs, fieldNames, fieldTypes, false);
+                       }
+                       else if(command.equals("insertbuttonreset"))
+                       {
+                               Hashtable htAttribs = new Hashtable();
+                               htAttribs.put("type", "reset");
+                               String[] fieldNames = { "name", "value" };
+                               String[] fieldTypes = { "text", "text" };
+                               insertFormElement(HTML.Tag.INPUT, "input", htAttribs, fieldNames, fieldTypes, false);
+                       }
+                       else if(command.equals("find"))
+                       {
+                               doSearch((String)null, (String)null, false, lastSearchCaseSetting, lastSearchTopSetting);
+                       }
+                       else if(command.equals("findagain"))
+                       {
+                               doSearch(lastSearchFindTerm, (String)null, false, lastSearchCaseSetting, false);
+                       }
+                       else if(command.equals("replace"))
+                       {
+                               doSearch((String)null, (String)null, true, lastSearchCaseSetting, lastSearchTopSetting);
+                       }
+                       else if(command.equals("exit"))
+                       {
+                               this.dispose();
+                       }
+                       else if(command.equals("helpabout"))
+                       {
+                               SimpleInfoDialog sidAbout = new SimpleInfoDialog(this.getFrame(), Translatrix.getTranslationString("About"), true, Translatrix.getTranslationString("AboutMessage"), SimpleInfoDialog.INFO);
+                       }
+                       else if(command.equals("spellcheck"))
+                       {
+                               spellCheck.checkSpelling(new DocumentWordTokenizer(jtpMain.getDocument()));
+                       }
+               }
+               catch(IOException ioe)
+               {
+                       logException("IOException in actionPerformed method", ioe);
+                       SimpleInfoDialog sidAbout = new SimpleInfoDialog(this.getFrame(), Translatrix.getTranslationString("Error"), true, Translatrix.getTranslationString("ErrorIOException"), SimpleInfoDialog.ERROR);
+               }
+               catch(BadLocationException ble)
+               {
+                       logException("BadLocationException in actionPerformed method", ble);
+                       SimpleInfoDialog sidAbout = new SimpleInfoDialog(this.getFrame(), Translatrix.getTranslationString("Error"), true, Translatrix.getTranslationString("ErrorBadLocationException"), SimpleInfoDialog.ERROR);
+               }
+               catch(NumberFormatException nfe)
+               {
+                       logException("NumberFormatException in actionPerformed method", nfe);
+                       SimpleInfoDialog sidAbout = new SimpleInfoDialog(this.getFrame(), Translatrix.getTranslationString("Error"), true, Translatrix.getTranslationString("ErrorNumberFormatException"), SimpleInfoDialog.ERROR);
+               }
+               catch(ClassNotFoundException cnfe)
+               {
+                       logException("ClassNotFound Exception in actionPerformed method", cnfe);
+                       SimpleInfoDialog sidAbout = new SimpleInfoDialog(this.getFrame(), Translatrix.getTranslationString("Error"), true, Translatrix.getTranslationString("ErrorClassNotFoundException "), SimpleInfoDialog.ERROR);
+               }
+               catch(RuntimeException re)
+               {
+                       logException("RuntimeException in actionPerformed method", re);
+                       SimpleInfoDialog sidAbout = new SimpleInfoDialog(this.getFrame(), Translatrix.getTranslationString("Error"), true, Translatrix.getTranslationString("ErrorRuntimeException"), SimpleInfoDialog.ERROR);
+               }
+       }
+
+       /* KeyListener methods */
+       public void keyTyped(KeyEvent ke)
+       {
+               Element elem;
+               String selectedText;
+               int pos = this.getCaretPosition();
+               int repos = -1;
+               if(ke.getKeyChar() == KeyEvent.VK_BACK_SPACE)
+               {
+                       try
+                       {
+                               if(pos > 0)
+                               {
+                                       if((selectedText = jtpMain.getSelectedText()) != null)
+                                       {
+                                               htmlUtilities.delete();
+                                               return;
+                                       }
+                                       else
+                                       {
+                                               int sOffset = htmlDoc.getParagraphElement(pos).getStartOffset();
+                                               if(sOffset == jtpMain.getSelectionStart())
+                                               {
+                                                       boolean content = true;
+                                                       if(htmlUtilities.checkParentsTag(HTML.Tag.LI))
+                                                       {
+                                                               elem = htmlUtilities.getListItemParent();
+                                                               content = false;
+                                                               int so = elem.getStartOffset();
+                                                               int eo = elem.getEndOffset();
+                                                               if(so + 1 < eo)
+                                                               {
+                                                                       char[] temp = jtpMain.getText(so, eo - so).toCharArray();
+                                                                       for(int i=0; i < temp.length; i++)
+                                                                       {
+                                                                               if(!(new Character(temp[i])).isWhitespace(temp[i]))
+                                                                               {
+                                                                                       content = true;
+                                                                               }
+                                                                       }
+                                                               }
+                                                               if(!content)
+                                                               {
+                                                                       Element listElement = elem.getParentElement();
+                                                                       htmlUtilities.removeTag(elem, true);
+                                                                       this.setCaretPosition(sOffset - 1);
+                                                                       return;
+                                                               }
+                                                               else
+                                                               {
+                                                                       jtpMain.setCaretPosition(jtpMain.getCaretPosition() - 1);
+                                                                       jtpMain.moveCaretPosition(jtpMain.getCaretPosition() - 2);
+                                                                       jtpMain.replaceSelection("");
+                                                                       return;
+                                                               }
+                                                       }
+                                                       else if(htmlUtilities.checkParentsTag(HTML.Tag.TABLE))
+                                                       {
+                                                               jtpMain.setCaretPosition(jtpMain.getCaretPosition() - 1);
+                                                               ke.consume();
+                                                               return;
+                                                       }
+                                               }
+                                               jtpMain.replaceSelection("");
+                                               return;
+                                       }
+                               }
+                       }
+                       catch (BadLocationException ble)
+                       {
+                               logException("BadLocationException in keyTyped method", ble);
+                               SimpleInfoDialog sidAbout = new SimpleInfoDialog(this.getFrame(), Translatrix.getTranslationString("Error"), true, Translatrix.getTranslationString("ErrorBadLocationException"), SimpleInfoDialog.ERROR);
+                       }
+                       catch (IOException ioe)
+                       {
+                               logException("IOException in keyTyped method", ioe);
+                               SimpleInfoDialog sidAbout = new SimpleInfoDialog(this.getFrame(), Translatrix.getTranslationString("Error"), true, Translatrix.getTranslationString("ErrorIOException"), SimpleInfoDialog.ERROR);
+                       }
+               }
+               else if(ke.getKeyChar() == KeyEvent.VK_ENTER)
+               {
+                       try
+                       {
+                               if(htmlUtilities.checkParentsTag(HTML.Tag.UL) == true | htmlUtilities.checkParentsTag(HTML.Tag.OL) == true)
+                               {
+                                       elem = htmlUtilities.getListItemParent();
+                                       int so = elem.getStartOffset();
+                                       int eo = elem.getEndOffset();
+                                       char[] temp = this.getTextPane().getText(so,eo-so).toCharArray();
+                                       boolean content = false;
+                                       for(int i=0;i<temp.length;i++)
+                                       {
+                                               if(!(new Character(temp[i])).isWhitespace(temp[i]))
+                                               {
+                                                       content = true;
+                                               }
+                                       }
+                                       if(content)
+                                       {
+                                               int end = -1;
+                                               int j = temp.length;
+                                               do
+                                               {
+                                                       j--;
+                                                       if(new Character(temp[j]).isLetterOrDigit(temp[j]))
+                                                       {
+                                                               end = j;
+                                                       }
+                                               } while (end == -1 && j >= 0);
+                                               j = end;
+                                               do
+                                               {
+                                                       j++;
+                                                       if(!new Character(temp[j]).isSpaceChar(temp[j]))
+                                                       {
+                                                               repos = j - end -1;
+                                                       }
+                                               } while (repos == -1 && j < temp.length);
+                                               if(repos == -1)
+                                               {
+                                                       repos = 0;
+                                               }
+                                       }
+                                       if(elem.getStartOffset() == elem.getEndOffset() || !content)
+                                       {
+                                               manageListElement(elem);
+                                       }
+                                       else
+                                       {
+                                               if(this.getCaretPosition() + 1 == elem.getEndOffset())
+                                               {
+                                                       insertListStyle(elem);
+                                                       this.setCaretPosition(pos - repos);
+                                               }
+                                               else
+                                               {
+                                                       int caret = this.getCaretPosition();
+                                                       String tempString = this.getTextPane().getText(caret, eo - caret);
+                                                       this.getTextPane().select(caret, eo - 1);
+                                                       this.getTextPane().replaceSelection("");
+                                                       htmlUtilities.insertListElement(tempString);
+                                                       Element newLi = htmlUtilities.getListItemParent();
+                                                       this.setCaretPosition(newLi.getEndOffset() - 1);
+                                               }
+                                       }
+                               }
+                       }
+                       catch (BadLocationException ble)
+                       {
+                               logException("BadLocationException in keyTyped method", ble);
+                               SimpleInfoDialog sidAbout = new SimpleInfoDialog(this.getFrame(), Translatrix.getTranslationString("Error"), true, Translatrix.getTranslationString("ErrorBadLocationException"), SimpleInfoDialog.ERROR);
+                       }
+                       catch (IOException ioe)
+                       {
+                               logException("IOException in keyTyped method", ioe);
+                               SimpleInfoDialog sidAbout = new SimpleInfoDialog(this.getFrame(), Translatrix.getTranslationString("Error"), true, Translatrix.getTranslationString("ErrorIOException"), SimpleInfoDialog.ERROR);
+                       }
+               }
+       }
+       public void keyPressed(KeyEvent e) {}
+       public void keyReleased(KeyEvent e) {}
+
+       public void insertListStyle(Element element)
+       throws BadLocationException,IOException
+       {
+               if(element.getParentElement().getName() == "ol")
+               {
+                       actionListOrdered.actionPerformed(new ActionEvent(new Object(), 0, "newListPoint"));
+               }
+               else
+               {
+                       actionListUnordered.actionPerformed(new ActionEvent(new Object(), 0, "newListPoint"));
+               }
+       }
+
+       /* DocumentListener methods */
+       public void changedUpdate(DocumentEvent de)     { handleDocumentChange(de); }
+       public void insertUpdate(DocumentEvent de)      { handleDocumentChange(de); }
+       public void removeUpdate(DocumentEvent de)      { handleDocumentChange(de); }
+       public void handleDocumentChange(DocumentEvent de)
+       {
+               if(!exclusiveEdit)
+               {
+                       if(jspSource.isShowing())
+                       {
+                               if(de.getDocument() instanceof HTMLDocument || de.getDocument() instanceof ExtendedHTMLDocument)
+                               {
+                                       jtpSource.getDocument().removeDocumentListener(this);
+                                       jtpSource.setText(jtpMain.getText());
+                                       jtpSource.getDocument().addDocumentListener(this);
+                               }
+                               else if(de.getDocument() instanceof PlainDocument || de.getDocument() instanceof DefaultStyledDocument)
+                               {
+                                       jtpMain.getDocument().removeDocumentListener(this);
+                                       jtpMain.setText(jtpSource.getText());
+                                       jtpMain.getDocument().addDocumentListener(this);
+                               }
+                       }
+               }
+       }
+
+       /* SpellCheckListener methods */
+       public void spellingError(SpellCheckEvent event)
+       {
+               spellDialog.show(event);
+       }
+
+       /** Method for setting a document as the current document for the text pane
+         * and re-registering the controls and settings for it
+         */
+       public void registerDocument(ExtendedHTMLDocument htmlDoc)
+       {
+               jtpMain.setDocument(htmlDoc);
+               jtpMain.getDocument().addUndoableEditListener(new CustomUndoableEditListener());
+               jtpMain.getDocument().addDocumentListener(this);
+               purgeUndos();
+               registerDocumentStyles();
+       }
+
+       /** Method for locating the available CSS style for the document and adding
+         * them to the styles selector
+         */
+       public void registerDocumentStyles()
+       {
+               if(jcmbStyleSelector == null || htmlDoc == null)
+               {
+                       return;
+               }
+               jcmbStyleSelector.setEnabled(false);
+               jcmbStyleSelector.removeAllItems();
+               jcmbStyleSelector.addItem(Translatrix.getTranslationString("NoCSSStyle"));
+               for(Enumeration e = htmlDoc.getStyleNames(); e.hasMoreElements();)
+               {
+                       String name = (String) e.nextElement();
+                       if(name.length() > 0 && name.charAt(0) == '.')
+                       {
+                               jcmbStyleSelector.addItem(name.substring(1));
+                       }
+               }
+               jcmbStyleSelector.setEnabled(true);
+       }
+
+       /** Method for inserting an HTML Table
+         */
+       private void insertTable(Hashtable attribs, String[] fieldNames, String[] fieldTypes)
+       throws IOException, BadLocationException, RuntimeException, NumberFormatException
+       {
+               int caretPos = jtpMain.getCaretPosition();
+               StringBuffer compositeElement = new StringBuffer("<TABLE");
+               if(attribs != null && attribs.size() > 0)
+               {
+                       Enumeration attribEntries = attribs.keys();
+                       while(attribEntries.hasMoreElements())
+                       {
+                               Object entryKey   = attribEntries.nextElement();
+                               Object entryValue = attribs.get(entryKey);
+                               if(entryValue != null && entryValue != "")
+                               {
+                                       compositeElement.append(" " + entryKey + "=" + '"' + entryValue + '"');
+                               }
+                       }
+               }
+               int rows = 0;
+               int cols = 0;
+               if(fieldNames != null && fieldNames.length > 0)
+               {
+                       PropertiesDialog propertiesDialog = new PropertiesDialog(this.getFrame(), fieldNames, fieldTypes, Translatrix.getTranslationString("FormDialogTitle"), true);
+                       propertiesDialog.show();
+                       String decision = propertiesDialog.getDecisionValue();
+                       if(decision.equals(Translatrix.getTranslationString("DialogCancel")))
+                       {
+                               propertiesDialog.dispose();
+                               propertiesDialog = null;
+                               return;
+                       }
+                       else
+                       {
+                               for(int iter = 0; iter < fieldNames.length; iter++)
+                               {
+                                       String fieldName = fieldNames[iter];
+                                       String propValue = propertiesDialog.getFieldValue(fieldName);
+                                       if(propValue != null && propValue != "" && propValue.length() > 0)
+                                       {
+                                               if(fieldName.equals("rows"))
+                                               {
+                                                       rows = Integer.parseInt(propValue);
+                                               }
+                                               else if(fieldName.equals("cols"))
+                                               {
+                                                       cols = Integer.parseInt(propValue);
+                                               }
+                                               else
+                                               {
+                                                       compositeElement.append(" " + fieldName + "=" + '"' + propValue + '"');
+                                               }
+                                       }
+                               }
+                       }
+                       propertiesDialog.dispose();
+                       propertiesDialog = null;
+               }
+               compositeElement.append(">");
+               for(int i = 0; i < rows; i++)
+               {
+                       compositeElement.append("<TR>");
+                       for(int j = 0; j < cols; j++)
+                       {
+                               compositeElement.append("<TD></TD>");
+                       }
+                       compositeElement.append("</TR>");
+               }
+               compositeElement.append("</TABLE><P>&nbsp;<P>");
+               htmlKit.insertHTML(htmlDoc, caretPos, compositeElement.toString(), 0, 0, HTML.Tag.TABLE);
+               jtpMain.setCaretPosition(caretPos + 1);
+               refreshOnUpdate();
+       }
+
+       /** Method for inserting a row into an HTML Table
+         */
+       private void insertTableRow()
+       {
+               int caretPos = jtpMain.getCaretPosition();
+               Element element = htmlDoc.getCharacterElement(jtpMain.getCaretPosition());
+               Element elementParent = element.getParentElement();
+               int startPoint  = -1;
+               int columnCount = -1;
+               while(elementParent != null && !elementParent.getName().equals("body"))
+               {
+                       if(elementParent.getName().equals("tr"))
+                       {
+                               startPoint  = elementParent.getStartOffset();
+                               columnCount = elementParent.getElementCount();
+                               break;
+                       }
+                       else
+                       {
+                               elementParent = elementParent.getParentElement();
+                       }
+               }
+               if(startPoint > -1 && columnCount > -1)
+               {
+                       jtpMain.setCaretPosition(startPoint);
+                       StringBuffer sRow = new StringBuffer();
+                       sRow.append("<TR>");
+                       for(int i = 0; i < columnCount; i++)
+                       {
+                               sRow.append("<TD></TD>");
+                       }
+                       sRow.append("</TR>");
+                       ActionEvent actionEvent = new ActionEvent(jtpMain, 0, "insertTableRow");
+                       new HTMLEditorKit.InsertHTMLTextAction("insertTableRow", sRow.toString(), HTML.Tag.TABLE, HTML.Tag.TR).actionPerformed(actionEvent);
+                       refreshOnUpdate();
+                       jtpMain.setCaretPosition(caretPos);
+               }
+       }
+
+       /** Method for inserting a column into an HTML Table
+         */
+       private void insertTableColumn()
+       {
+               int caretPos = jtpMain.getCaretPosition();
+               Element element = htmlDoc.getCharacterElement(jtpMain.getCaretPosition());
+               Element elementParent = element.getParentElement();
+               int startPoint = -1;
+               int rowCount   = -1;
+               int cellOffset =  0;
+               while(elementParent != null && !elementParent.getName().equals("body"))
+               {
+                       if(elementParent.getName().equals("table"))
+                       {
+                               startPoint = elementParent.getStartOffset();
+                               rowCount   = elementParent.getElementCount();
+                               break;
+                       }
+                       else if(elementParent.getName().equals("tr"))
+                       {
+                               int rowStart = elementParent.getStartOffset();
+                               int rowCells = elementParent.getElementCount();
+                               for(int i = 0; i < rowCells; i++)
+                               {
+                                       Element currentCell = elementParent.getElement(i);
+                                       if(jtpMain.getCaretPosition() >= currentCell.getStartOffset() && jtpMain.getCaretPosition() <= currentCell.getEndOffset())
+                                       {
+                                               cellOffset = i;
+                                       }
+                               }
+                               elementParent = elementParent.getParentElement();
+                       }
+                       else
+                       {
+                               elementParent = elementParent.getParentElement();
+                       }
+               }
+               if(startPoint > -1 && rowCount > -1)
+               {
+                       jtpMain.setCaretPosition(startPoint);
+                       String sCell = "<TD></TD>";
+                       ActionEvent actionEvent = new ActionEvent(jtpMain, 0, "insertTableCell");
+                       for(int i = 0; i < rowCount; i++)
+                       {
+                               Element row = elementParent.getElement(i);
+                               Element whichCell = row.getElement(cellOffset);
+                               jtpMain.setCaretPosition(whichCell.getStartOffset());
+                               new HTMLEditorKit.InsertHTMLTextAction("insertTableCell", sCell, HTML.Tag.TR, HTML.Tag.TD, HTML.Tag.TH, HTML.Tag.TD).actionPerformed(actionEvent);
+                       }
+                       refreshOnUpdate();
+                       jtpMain.setCaretPosition(caretPos);
+               }
+       }
+
+       /** Method for inserting a cell into an HTML Table
+         */
+       private void insertTableCell()
+       {
+               String sCell = "<TD></TD>";
+               ActionEvent actionEvent = new ActionEvent(jtpMain, 0, "insertTableCell");
+               new HTMLEditorKit.InsertHTMLTextAction("insertTableCell", sCell, HTML.Tag.TR, HTML.Tag.TD, HTML.Tag.TH, HTML.Tag.TD).actionPerformed(actionEvent);
+               refreshOnUpdate();
+       }
+
+       /** Method for deleting a row from an HTML Table
+         */
+       private void deleteTableRow()
+       throws BadLocationException
+       {
+               int caretPos = jtpMain.getCaretPosition();
+               Element element = htmlDoc.getCharacterElement(jtpMain.getCaretPosition());
+               Element elementParent = element.getParentElement();
+               int startPoint = -1;
+               int endPoint   = -1;
+               while(elementParent != null && !elementParent.getName().equals("body"))
+               {
+                       if(elementParent.getName().equals("tr"))
+                       {
+                               startPoint = elementParent.getStartOffset();
+                               endPoint   = elementParent.getEndOffset();
+                               break;
+                       }
+                       else
+                       {
+                               elementParent = elementParent.getParentElement();
+                       }
+               }
+               if(startPoint > -1 && endPoint > startPoint)
+               {
+                       htmlDoc.remove(startPoint, endPoint - startPoint);
+                       jtpMain.setDocument(htmlDoc);
+                       registerDocument(htmlDoc);
+                       refreshOnUpdate();
+                       if(caretPos >= htmlDoc.getLength())
+                       {
+                               caretPos = htmlDoc.getLength() - 1;
+                       }
+                       jtpMain.setCaretPosition(caretPos);
+               }
+       }
+
+       /** Method for deleting a column from an HTML Table
+         */
+       private void deleteTableColumn()
+       throws BadLocationException
+       {
+               int caretPos = jtpMain.getCaretPosition();
+               Element element       = htmlDoc.getCharacterElement(jtpMain.getCaretPosition());
+               Element elementParent = element.getParentElement();
+               Element elementCell   = (Element)null;
+               Element elementRow    = (Element)null;
+               Element elementTable  = (Element)null;
+               // Locate the table, row, and cell location of the cursor
+               while(elementParent != null && !elementParent.getName().equals("body"))
+               {
+                       if(elementParent.getName().equals("td"))
+                       {
+                               elementCell = elementParent;
+                       }
+                       else if(elementParent.getName().equals("tr"))
+                       {
+                               elementRow = elementParent;
+                       }
+                       else if(elementParent.getName().equals("table"))
+                       {
+                               elementTable = elementParent;
+                       }
+                       elementParent = elementParent.getParentElement();
+               }
+               int whichColumn = -1;
+               if(elementCell != null && elementRow != null && elementTable != null)
+               {
+                       // Find the column the cursor is in
+                       for(int i = 0; i < elementRow.getElementCount(); i++)
+                       {
+                               if(elementCell == elementRow.getElement(i))
+                               {
+                                       whichColumn = i;
+                               }
+                       }
+                       if(whichColumn > -1)
+                       {
+                               // Iterate through the table rows, deleting cells from the indicated column
+                               for(int i = 0; i < elementTable.getElementCount(); i++)
+                               {
+                                       elementRow  = elementTable.getElement(i);
+                                       elementCell = (elementRow.getElementCount() > whichColumn ? elementRow.getElement(whichColumn) : elementRow.getElement(elementRow.getElementCount() - 1));
+                                       int columnCellStart = elementCell.getStartOffset();
+                                       int columnCellEnd   = elementCell.getEndOffset();
+                                       htmlDoc.remove(columnCellStart, columnCellEnd - columnCellStart);
+                               }
+                               jtpMain.setDocument(htmlDoc);
+                               registerDocument(htmlDoc);
+                               refreshOnUpdate();
+                               if(caretPos >= htmlDoc.getLength())
+                               {
+                                       caretPos = htmlDoc.getLength() - 1;
+                               }
+                               jtpMain.setCaretPosition(caretPos);
+                       }
+               }
+       }
+
+       /** Method for inserting a break (BR) element
+         */
+       private void insertBreak()
+       throws IOException, BadLocationException, RuntimeException
+       {
+               int caretPos = jtpMain.getCaretPosition();
+               htmlKit.insertHTML(htmlDoc, caretPos, "<BR>", 0, 0, HTML.Tag.BR);
+               jtpMain.setCaretPosition(caretPos + 1);
+       }
+
+       /** Method for inserting a non-breaking space (&nbsp;)
+         */
+       private void insertNonbreakingSpace()
+       throws IOException, BadLocationException, RuntimeException
+       {
+               int caretPos = jtpMain.getCaretPosition();
+               htmlDoc.insertString(caretPos, "\240", jtpMain.getInputAttributes());
+               jtpMain.setCaretPosition(caretPos + 1);
+       }
+
+       /** Method for inserting a form element
+         */
+       private void insertFormElement(HTML.Tag baseTag, String baseElement, Hashtable attribs, String[] fieldNames, String[] fieldTypes, String[] fieldValues, boolean hasClosingTag)
+       throws IOException, BadLocationException, RuntimeException
+       {
+               int caretPos = jtpMain.getCaretPosition();
+               StringBuffer compositeElement = new StringBuffer("<" + baseElement);
+               if(attribs != null && attribs.size() > 0)
+               {
+                       Enumeration attribEntries = attribs.keys();
+                       while(attribEntries.hasMoreElements())
+                       {
+                               Object entryKey   = attribEntries.nextElement();
+                               Object entryValue = attribs.get(entryKey);
+                               if(entryValue != null && entryValue != "")
+                               {
+                                       compositeElement.append(" " + entryKey + "=" + '"' + entryValue + '"');
+                               }
+                       }
+               }
+               if(fieldNames != null && fieldNames.length > 0)
+               {
+                       PropertiesDialog propertiesDialog = new PropertiesDialog(this.getFrame(), fieldNames, fieldTypes, fieldValues, Translatrix.getTranslationString("FormDialogTitle"), true);
+                       propertiesDialog.show();
+                       String decision = propertiesDialog.getDecisionValue();
+                       if(decision.equals(Translatrix.getTranslationString("DialogCancel")))
+                       {
+                               propertiesDialog.dispose();
+                               propertiesDialog = null;
+                               return;
+                       }
+                       else
+                       {
+                               for(int iter = 0; iter < fieldNames.length; iter++)
+                               {
+                                       String fieldName = fieldNames[iter];
+                                       String propValue = propertiesDialog.getFieldValue(fieldName);
+                                       if(propValue != null && propValue.length() > 0)
+                                       {
+                                               if(fieldName.equals("checked"))
+                                               {
+                                                       if(propValue.equals("true"))
+                                                       {
+                                                               compositeElement.append(" " + fieldName + "=" + '"' + propValue + '"');
+                                                       }
+                                               }
+                                               else
+                                               {
+                                                       compositeElement.append(" " + fieldName + "=" + '"' + propValue + '"');
+                                               }
+                                       }
+                               }
+                       }
+                       propertiesDialog.dispose();
+                       propertiesDialog = null;
+               }
+               // --- Convenience for editing, this makes the FORM visible
+               if(useFormIndicator && baseElement.equals("form"))
+               {
+                       compositeElement.append(" bgcolor=" + '"' + clrFormIndicator + '"');
+               }
+               // --- END
+               compositeElement.append(">");
+               if(hasClosingTag)
+               {
+                       compositeElement.append("</" + baseElement + ">");
+               }
+               if(baseTag == HTML.Tag.FORM)
+               {
+                       compositeElement.append("<P>&nbsp;</P>");
+               }
+               htmlKit.insertHTML(htmlDoc, caretPos, compositeElement.toString(), 0, 0, baseTag);
+               // jtpMain.setCaretPosition(caretPos + 1);
+               refreshOnUpdate();
+       }
+
+       /** Alternate method call for inserting a form element
+         */
+       private void insertFormElement(HTML.Tag baseTag, String baseElement, Hashtable attribs, String[] fieldNames, String[] fieldTypes, boolean hasClosingTag)
+       throws IOException, BadLocationException, RuntimeException
+       {
+               insertFormElement(baseTag, baseElement, attribs, fieldNames, fieldTypes, new String[fieldNames.length], hasClosingTag);
+       }
+
+       /** Method that handles initial list insertion and deletion
+         */
+       public void manageListElement(Element element)
+       {
+               Element h = htmlUtilities.getListItemParent();
+               Element listElement = h.getParentElement();
+               if(h != null)
+               {
+                       htmlUtilities.removeTag(h, true);
+               }
+       }
+
+       /** Method to initiate a find/replace operation
+         */
+       private void doSearch(String searchFindTerm, String searchReplaceTerm, boolean bIsFindReplace, boolean bCaseSensitive, boolean bStartAtTop)
+       {
+               boolean bReplaceAll = false;
+               JTextPane searchPane = jtpMain;
+               if(jspSource.isShowing() || jtpSource.hasFocus())
+               {
+                       searchPane = jtpSource;
+               }
+               if(searchFindTerm == null || (bIsFindReplace && searchReplaceTerm == null))
+               {
+                       SearchDialog sdSearchInput = new SearchDialog(this.getFrame(), Translatrix.getTranslationString("SearchDialogTitle"), true, bIsFindReplace, bCaseSensitive, bStartAtTop);
+                       searchFindTerm    = sdSearchInput.getFindTerm();
+                       searchReplaceTerm = sdSearchInput.getReplaceTerm();
+                       bCaseSensitive    = sdSearchInput.getCaseSensitive();
+                       bStartAtTop       = sdSearchInput.getStartAtTop();
+                       bReplaceAll       = sdSearchInput.getReplaceAll();
+               }
+               if(searchFindTerm != null && (!bIsFindReplace || searchReplaceTerm != null))
+               {
+                       if(bReplaceAll)
+                       {
+                               int results = findText(searchFindTerm, searchReplaceTerm, bCaseSensitive, 0);
+                               int findOffset = 0;
+                               if(results > -1)
+                               {
+                                       while(results > -1)
+                                       {
+                                               findOffset = findOffset + searchReplaceTerm.length();
+                                               results    = findText(searchFindTerm, searchReplaceTerm, bCaseSensitive, findOffset);
+                                       }
+                               }
+                               else
+                               {
+                                       SimpleInfoDialog sidWarn = new SimpleInfoDialog(this.getFrame(), "", true, Translatrix.getTranslationString("ErrorNoOccurencesFound") + ":\n" + searchFindTerm, SimpleInfoDialog.WARNING);
+                               }
+                       }
+                       else
+                       {
+                               int results = findText(searchFindTerm, searchReplaceTerm, bCaseSensitive, (bStartAtTop ? 0 : searchPane.getCaretPosition()));
+                               if(results == -1)
+                               {
+                                       SimpleInfoDialog sidWarn = new SimpleInfoDialog(this.getFrame(), "", true, Translatrix.getTranslationString("ErrorNoMatchFound") + ":\n" + searchFindTerm, SimpleInfoDialog.WARNING);
+                               }
+                       }
+                       lastSearchFindTerm    = new String(searchFindTerm);
+                       if(searchReplaceTerm != null)
+                       {
+                               lastSearchReplaceTerm = new String(searchReplaceTerm);
+                       }
+                       else
+                       {
+                               lastSearchReplaceTerm = (String)null;
+                       }
+                       lastSearchCaseSetting = bCaseSensitive;
+                       lastSearchTopSetting  = bStartAtTop;
+               }
+       }
+
+       /** Method for finding (and optionally replacing) a string in the text
+         */
+       private int findText(String findTerm, String replaceTerm, boolean bCaseSenstive, int iOffset)
+       {
+               JTextPane jtpFindSource;
+               if(jspSource.isShowing() || jtpSource.hasFocus())
+               {
+                       jtpFindSource = jtpSource;
+               }
+               else
+               {
+                       jtpFindSource = jtpMain;
+               }
+               int searchPlace = -1;
+               try
+               {
+                       Document baseDocument = jtpFindSource.getDocument();
+                       searchPlace =
+                               (bCaseSenstive ?
+                                       baseDocument.getText(0, baseDocument.getLength()).indexOf(findTerm, iOffset) :
+                                       baseDocument.getText(0, baseDocument.getLength()).toLowerCase().indexOf(findTerm.toLowerCase(), iOffset)
+                               );
+                       if(searchPlace > -1)
+                       {
+                               if(replaceTerm != null)
+                               {
+                                       AttributeSet attribs = null;
+                                       if(baseDocument instanceof HTMLDocument)
+                                       {
+                                               Element element = ((HTMLDocument)baseDocument).getCharacterElement(searchPlace);
+                                               attribs = element.getAttributes();
+                                       }
+                                       baseDocument.remove(searchPlace, findTerm.length());
+                                       baseDocument.insertString(searchPlace, replaceTerm, attribs);
+                                       jtpFindSource.setCaretPosition(searchPlace + replaceTerm.length());
+                                       jtpFindSource.requestFocus();
+                                       jtpFindSource.select(searchPlace, searchPlace + replaceTerm.length());
+                               }
+                               else
+                               {
+                                       jtpFindSource.setCaretPosition(searchPlace + findTerm.length());
+                                       jtpFindSource.requestFocus();
+                                       jtpFindSource.select(searchPlace, searchPlace + findTerm.length());
+                               }
+                       }
+               }
+               catch(BadLocationException ble)
+               {
+                       logException("BadLocationException in actionPerformed method", ble);
+                       SimpleInfoDialog sidAbout = new SimpleInfoDialog(this.getFrame(), Translatrix.getTranslationString("Error"), true, Translatrix.getTranslationString("ErrorBadLocationException"), SimpleInfoDialog.ERROR);
+               }
+               return searchPlace;
+       }
+
+       /** Method for inserting an image from a file
+         */
+       private void insertLocalImage(File whatImage)
+       throws IOException, BadLocationException, RuntimeException
+       {
+               if(whatImage == null)
+               {
+                       whatImage = getImageFromChooser(".", extsIMG, Translatrix.getTranslationString("FiletypeIMG"));
+               }
+               if(whatImage != null)
+               {
+                       int caretPos = jtpMain.getCaretPosition();
+                       htmlKit.insertHTML(htmlDoc, caretPos, "<IMG SRC=\"" + whatImage + "\">", 0, 0, HTML.Tag.IMG);
+                       jtpMain.setCaretPosition(caretPos + 1);
+                       refreshOnUpdate();
+               }
+       }
+
+       /** Method for inserting an image from a server
+         */
+       private void insertServerImage()
+       throws BadLocationException
+       {
+               if(ServletURL != null)
+               {
+                       try
+                       {
+                               URL theServlet = new URL(ServletURL + "?GetImages=" + TreePilotSystemID + "&ImageExtensions=" + TreePilotProperties.getString("ValidImageExtensions"));
+                               URLConnection conn = theServlet.openConnection();
+                               ObjectInputStream in = new ObjectInputStream(conn.getInputStream());
+                               String[] imageList = (String[]) in.readObject();
+                               int caretPos = jtpMain.getCaretPosition();
+                               ImageDialog imageDialog = new ImageDialog(this, ImageDir + TreePilotSystemID, imageList, "Image Chooser", true);
+                               String selectedImage = imageDialog.getSelectedImage();
+                               imageDialog.dispose();
+                               if(selectedImage != null  && !selectedImage.equals(""))
+                               {
+                                       htmlKit.insertHTML(htmlDoc, caretPos, selectedImage, 0, 0, HTML.Tag.IMG);
+                                       jtpMain.setCaretPosition(caretPos + 1);
+                               }
+                               jtpMain.requestFocus();
+                               in.close();
+                       }
+                       catch (MalformedURLException mue)
+                       {
+                               System.err.println("MalFormedURLException during insertImage " + mue);
+                       }
+                       catch (IOException ie)
+                       {
+                               System.err.println("IOException during insertImage " + ie);
+                       }
+                       catch (ClassNotFoundException cnfe)
+                       {
+                               System.err.println("ClassNotFoundException during insertImage" + cnfe);
+                       }
+               }
+       }
+
+       /** Method for inserting an image
+         */
+       public String insertFile()
+       {
+               String selectedFile = null;
+               if(ServletURL != null)
+               {
+                       try
+                       {
+                               URL theServlet = new URL(ServletURL + "?GetFiles=" + TreePilotSystemID + "&FileExtensions=" + TreePilotProperties.getString("ValidFileExtensions"));
+                               URLConnection conn = theServlet.openConnection();
+                               ObjectInputStream in = new ObjectInputStream(conn.getInputStream());
+                               String[] fileList = (String[]) in.readObject();
+                               FileDialog fileDialog = new FileDialog(this, ImageDir + TreePilotSystemID, fileList, "File Chooser", true);
+                               selectedFile = fileDialog.getSelectedFile();
+                               fileDialog.dispose();
+                               in.close();
+                       }
+                       catch (MalformedURLException mue)
+                       {
+                               System.err.println("MalFormedURLException during insertFile " + mue);
+                       }
+                       catch (IOException ie)
+                       {
+                               System.err.println("IOException during insertFile " + ie);
+                       }
+                       catch (ClassNotFoundException cnfe)
+                       {
+                               System.err.println("ClassNotFoundException during insertFile" + cnfe);
+                       }
+               }
+               return selectedFile;
+       }
+
+       /** Method for saving text as a complete HTML document
+         */
+       private void writeOut(HTMLDocument doc, File whatFile)
+       throws IOException, BadLocationException
+       {
+               if(whatFile == null)
+               {
+                       whatFile = getFileFromChooser(".", JFileChooser.SAVE_DIALOG, extsHTML, Translatrix.getTranslationString("FiletypeHTML"));
+               }
+               if(whatFile != null)
+               {
+                       FileWriter fw = new FileWriter(whatFile);
+                       htmlKit.write(fw, doc, 0, doc.getLength());
+                       fw.flush();
+                       fw.close();
+                       currentFile = whatFile;
+                       updateTitle();
+               }
+               refreshOnUpdate();
+       }
+
+       /** Method for saving text as an HTML fragment
+         */
+       private void writeOutFragment(HTMLDocument doc, String containingTag)
+       throws IOException, BadLocationException
+       {
+               File whatFile = getFileFromChooser(".", JFileChooser.SAVE_DIALOG, extsHTML, Translatrix.getTranslationString("FiletypeHTML"));
+               if(whatFile != null)
+               {
+                       FileWriter fw = new FileWriter(whatFile);
+//                     Element eleBody = locateElementInDocument((StyledDocument)doc, containingTag);
+//                     htmlKit.write(fw, doc, eleBody.getStartOffset(), eleBody.getEndOffset());
+                       String docTextCase = jtpSource.getText().toLowerCase();
+                       int tagStart       = docTextCase.indexOf("<" + containingTag.toLowerCase());
+                       int tagStartClose  = docTextCase.indexOf(">", tagStart) + 1;
+                       String closeTag    = "</" + containingTag.toLowerCase() + ">";
+                       int tagEndOpen     = docTextCase.indexOf(closeTag);
+                       if(tagStartClose < 0) { tagStartClose = 0; }
+                       if(tagEndOpen < 0 || tagEndOpen > docTextCase.length()) { tagEndOpen = docTextCase.length(); }
+                       String bodyText = jtpSource.getText().substring(tagStartClose, tagEndOpen);
+                       fw.write(bodyText, 0, bodyText.length());
+                       fw.flush();
+                       fw.close();
+               }
+               refreshOnUpdate();
+       }
+
+       /** Method for saving text as an RTF document
+         */
+       private void writeOutRTF(StyledDocument doc)
+       throws IOException, BadLocationException
+       {
+               File whatFile = getFileFromChooser(".", JFileChooser.SAVE_DIALOG, extsRTF, Translatrix.getTranslationString("FiletypeRTF"));
+               if(whatFile != null)
+               {
+                       FileOutputStream fos = new FileOutputStream(whatFile);
+                       RTFEditorKit rtfKit = new RTFEditorKit();
+                       rtfKit.write(fos, doc, 0, doc.getLength());
+                       fos.flush();
+                       fos.close();
+               }
+               refreshOnUpdate();
+       }
+
+       /** Method for saving text as a Base64 encoded document
+         */
+       private void writeOutBase64(String text)
+       throws IOException, BadLocationException
+       {
+               File whatFile = getFileFromChooser(".", JFileChooser.SAVE_DIALOG, extsB64, Translatrix.getTranslationString("FiletypeB64"));
+               if(whatFile != null)
+               {
+                       String base64text = Base64Codec.encode(text);
+                       FileWriter fw = new FileWriter(whatFile);
+                       fw.write(base64text, 0, base64text.length());
+                       fw.flush();
+                       fw.close();
+               }
+               refreshOnUpdate();
+       }
+
+       /** Method to invoke loading HTML into the app
+         */
+       private void openDocument(File whatFile)
+       throws IOException, BadLocationException
+       {
+               if(whatFile == null)
+               {
+                       whatFile = getFileFromChooser(".", JFileChooser.OPEN_DIALOG, extsHTML, Translatrix.getTranslationString("FiletypeHTML"));
+               }
+               if(whatFile != null)
+               {
+                       try
+                       {
+                               loadDocument(whatFile, null);
+                       }
+                       catch(ChangedCharSetException ccse)
+                       {
+                               String charsetType = ccse.getCharSetSpec().toLowerCase();
+                               int pos = charsetType.indexOf("charset");
+                               if(pos == -1)
+                               {
+                                       throw ccse;
+                               }
+                               while(pos < charsetType.length() && charsetType.charAt(pos) != '=')
+                               {
+                                       pos++;
+                               }
+                               pos++; // Places file cursor past the equals sign (=)
+                               String whatEncoding = charsetType.substring(pos).trim();
+                               loadDocument(whatFile, whatEncoding);
+                       }
+               }
+               refreshOnUpdate();
+       }
+
+       /** Method for loading HTML document into the app, including document encoding setting
+         */
+       private void loadDocument(File whatFile, String whatEncoding)
+       throws IOException, BadLocationException
+       {
+               Reader r = null;
+               htmlDoc = (ExtendedHTMLDocument)(htmlKit.createDefaultDocument());
+               try
+               {
+                       if(whatEncoding == null)
+                       {
+                               r = new InputStreamReader(new FileInputStream(whatFile));
+                       }
+                       else
+                       {
+                               r = new InputStreamReader(new FileInputStream(whatFile), whatEncoding);
+                               htmlDoc.putProperty("IgnoreCharsetDirective", new Boolean(true));
+                       }
+                       htmlKit.read(r, htmlDoc, 0);
+                       r.close();
+                       registerDocument(htmlDoc);
+                       jtpSource.setText(jtpMain.getText());
+                       currentFile = whatFile;
+                       updateTitle();
+               }
+               finally
+               {
+                       if(r != null)
+                       {
+                               r.close();
+                       }
+               }
+       }
+
+       /** Method for loading a Base64 encoded document
+         */
+       private void openDocumentBase64(File whatFile)
+       throws IOException, BadLocationException
+       {
+               if(whatFile == null)
+               {
+                       whatFile = getFileFromChooser(".", JFileChooser.OPEN_DIALOG, extsB64, Translatrix.getTranslationString("FiletypeB64"));
+               }
+               if(whatFile != null)
+               {
+                       FileReader fr = new FileReader(whatFile);
+                       int nextChar = 0;
+                       StringBuffer encodedText = new StringBuffer();
+                       try
+                       {
+                               while((nextChar = fr.read()) != -1)
+                               {
+                                       encodedText.append((char)nextChar);
+                               }
+                               fr.close();
+                               jtpSource.setText(Base64Codec.decode(encodedText.toString()));
+                               jtpMain.setText(jtpSource.getText());
+                               registerDocument((ExtendedHTMLDocument)(jtpMain.getDocument()));
+                       }
+                       finally
+                       {
+                               if(fr != null)
+                               {
+                                       fr.close();
+                               }
+                       }
+               }
+       }
+
+       /** Method for loading a Stylesheet into the app
+         */
+       private void openStyleSheet(File fileCSS)
+       throws IOException
+       {
+               if(fileCSS == null)
+               {
+                       fileCSS = getFileFromChooser(".", JFileChooser.OPEN_DIALOG, extsCSS, Translatrix.getTranslationString("FiletypeCSS"));
+               }
+               if(fileCSS != null)
+               {
+                       String currDocText = jtpMain.getText();
+                       htmlDoc = (ExtendedHTMLDocument)(htmlKit.createDefaultDocument());
+                       styleSheet = htmlDoc.getStyleSheet();
+                       URL cssUrl = fileCSS.toURL();
+                       InputStream is = cssUrl.openStream();
+                       BufferedReader br = new BufferedReader(new InputStreamReader(is));
+                       styleSheet.loadRules(br, cssUrl);
+                       br.close();
+                       htmlDoc = new ExtendedHTMLDocument(styleSheet);
+                       registerDocument(htmlDoc);
+                       jtpMain.setText(currDocText);
+                       jtpSource.setText(jtpMain.getText());
+               }
+               refreshOnUpdate();
+       }
+
+       /** Method for serializing the document out to a file
+         */
+       public void serializeOut(HTMLDocument doc)
+       throws IOException
+       {
+               File whatFile = getFileFromChooser(".", JFileChooser.SAVE_DIALOG, extsSer, Translatrix.getTranslationString("FiletypeSer"));
+               if(whatFile != null)
+               {
+                       ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(whatFile));
+                       oos.writeObject(doc);
+                       oos.flush();
+                       oos.close();
+               }
+               refreshOnUpdate();
+       }
+
+       /** Method for reading in a serialized document from a file
+         */
+       public void serializeIn()
+       throws IOException, ClassNotFoundException
+       {
+               File whatFile = getFileFromChooser(".", JFileChooser.OPEN_DIALOG, extsSer, Translatrix.getTranslationString("FiletypeSer"));
+               if(whatFile != null)
+               {
+                       ObjectInputStream ois = new ObjectInputStream(new FileInputStream(whatFile));
+                       htmlDoc = (ExtendedHTMLDocument)(ois.readObject());
+                       ois.close();
+                       registerDocument(htmlDoc);
+                       validate();
+               }
+               refreshOnUpdate();
+       }
+
+       /** Method for obtaining a File for input/output using a JFileChooser dialog
+         */
+       private File getFileFromChooser(String startDir, int dialogType, String[] exts, String desc)
+       {
+               JFileChooser jfileDialog = new JFileChooser(startDir);
+               jfileDialog.setDialogType(dialogType);
+               jfileDialog.setFileFilter(new MutableFilter(exts, desc));
+               int optionSelected = JFileChooser.CANCEL_OPTION;
+               if(dialogType == JFileChooser.OPEN_DIALOG)
+               {
+                       optionSelected = jfileDialog.showOpenDialog(this);
+               }
+               else if(dialogType == JFileChooser.SAVE_DIALOG)
+               {
+                       optionSelected = jfileDialog.showSaveDialog(this);
+               }
+               else // default to an OPEN_DIALOG
+               {
+                       optionSelected = jfileDialog.showOpenDialog(this);
+               }
+               if(optionSelected == JFileChooser.APPROVE_OPTION)
+               {
+                       return jfileDialog.getSelectedFile();
+               }
+               return (File)null;
+       }
+
+       /** Method for obtaining an Image for input using a custom JFileChooser dialog
+         */
+       private File getImageFromChooser(String startDir, String[] exts, String desc)
+       {
+               ImageFileChooser jImageDialog = new ImageFileChooser(startDir);
+               jImageDialog.setDialogType(JFileChooser.CUSTOM_DIALOG);
+               jImageDialog.setFileFilter(new MutableFilter(exts, desc));
+               jImageDialog.setDialogTitle(Translatrix.getTranslationString("ImageDialogTitle"));
+               int optionSelected = JFileChooser.CANCEL_OPTION;
+               optionSelected = jImageDialog.showDialog(this, Translatrix.getTranslationString("Insert"));
+               if(optionSelected == JFileChooser.APPROVE_OPTION)
+               {
+                       return jImageDialog.getSelectedFile();
+               }
+               return (File)null;
+       }
+
+       /** Method for describing the node hierarchy of the document
+         */
+       private void describeDocument(StyledDocument doc)
+       {
+               Element[] elements = doc.getRootElements();
+               for(int i = 0; i < elements.length; i++)
+               {
+                       indent = indentStep;
+                       for(int j = 0; j < indent; j++) { System.out.print(" "); }
+                       System.out.print(elements[i]);
+                       traverseElement(elements[i]);
+                       System.out.println("");
+               }
+       }
+
+       /** Traverses nodes for the describing method
+         */
+       private void traverseElement(Element element)
+       {
+               indent += indentStep;
+               for(int i = 0; i < element.getElementCount(); i++)
+               {
+                       for(int j = 0; j < indent; j++) { System.out.print(" "); }
+                       System.out.print(element.getElement(i));
+                       traverseElement(element.getElement(i));
+               }
+               indent -= indentStep;
+       }
+
+       /** Method to locate a node element by name
+         */
+       private Element locateElementInDocument(StyledDocument doc, String elementName)
+       {
+               Element[] elements = doc.getRootElements();
+               for(int i = 0; i < elements.length; i++)
+               {
+                       if(elements[i].getName().equalsIgnoreCase(elementName))
+                       {
+                               return elements[i];
+                       }
+                       else
+                       {
+                               Element rtnElement = locateChildElementInDocument(elements[i], elementName);
+                               if(rtnElement != null)
+                               {
+                                       return rtnElement;
+                               }
+                       }
+               }
+               return (Element)null;
+       }
+
+       /** Traverses nodes for the locating method
+         */
+       private Element locateChildElementInDocument(Element element, String elementName)
+       {
+               for(int i = 0; i < element.getElementCount(); i++)
+               {
+                       if(element.getElement(i).getName().equalsIgnoreCase(elementName))
+                       {
+                               return element.getElement(i);
+                       }
+               }
+               return (Element)null;
+       }
+
+       /** Convenience method for obtaining the WYSIWYG JTextPane
+         */
+       public JTextPane getTextPane()
+       {
+               return jtpMain;
+       }
+
+       /** Convenience method for obtaining the Source JTextPane
+         */
+       public JTextPane getSourcePane()
+       {
+               return jtpSource;
+       }
+
+       /** Convenience method for obtaining the application as a Frame
+         */
+       public Frame getFrame()
+       {
+               return frameHandler;
+       }
+
+       /** Convenience method for setting the parent Frame
+         */
+       public void setFrame(Frame parentFrame)
+       {
+               frameHandler = parentFrame;
+       }
+
+       /** Convenience method for obtaining the pre-generated menu bar
+         */
+       public JMenuBar getMenuBar()
+       {
+               return jMenuBar;
+       }
+
+       /** Convenience method for obtaining a custom menu bar
+         */
+       public JMenuBar getCustomMenuBar(Vector vcMenus)
+       {
+               jMenuBar = new JMenuBar();
+               for(int i = 0; i < vcMenus.size(); i++)
+               {
+                       String menuToAdd = ((String)(vcMenus.elementAt(i))).toLowerCase();
+                       if(htMenus.containsKey(menuToAdd))
+                       {
+                               jMenuBar.add((JMenu)(htMenus.get(menuToAdd)));
+                       }
+               }
+               return jMenuBar;
+       }
+
+       /** Convenience method for obtaining the pre-generated toolbar
+         */
+       public JToolBar getToolBar(boolean isShowing)
+       {
+               jcbmiViewToolbar.setState(isShowing);
+               return jToolBar;
+       }
+
+       /** Convenience method for obtaining the pre-generated toolbar
+         */
+       public JToolBar getCustomToolBar(Vector vcTools, boolean isShowing)
+       {
+               jcbmiViewToolbar.setState(isShowing);
+               jToolBar = new JToolBar(JToolBar.HORIZONTAL);
+               jToolBar.setFloatable(false);
+               for(int i = 0; i < vcTools.size(); i++)
+               {
+                       String toolToAdd = ((String)(vcTools.elementAt(i))).toLowerCase();
+                       if(toolToAdd.equals(KEY_TOOL_SEP))
+                       {
+                               jToolBar.add(new JToolBar.Separator());
+                       }
+                       else if(htTools.containsKey(toolToAdd))
+                       {
+                               if(htTools.get(toolToAdd) instanceof JButtonNoFocus)
+                               {
+                                       jToolBar.add((JButtonNoFocus)(htTools.get(toolToAdd)));
+                               }
+                               else if(htTools.get(toolToAdd) instanceof JToggleButtonNoFocus)
+                               {
+                                       jToolBar.add((JToggleButtonNoFocus)(htTools.get(toolToAdd)));
+                               }
+                               else if(htTools.get(toolToAdd) instanceof JComboBoxNoFocus)
+                               {
+                                       jToolBar.add((JComboBoxNoFocus)(htTools.get(toolToAdd)));
+                               }
+                               else
+                               {
+                                       jToolBar.add((JComponent)(htTools.get(toolToAdd)));
+                               }
+                       }
+               }
+               return jToolBar;
+       }
+
+       /** Convenience method for obtaining the current file handle
+         */
+       public File getCurrentFile()
+       {
+               return currentFile;
+       }
+
+       /** Convenience method for obtaining the application name
+         */
+       public String getAppName()
+       {
+               return appName;
+       }
+
+       /** Convenience method for obtaining the document text
+         */
+       public String getDocumentText()
+       {
+               return jtpMain.getText();
+       }
+
+       /** Convenience method for obtaining the document text
+         * contained within a tag pair
+         */
+       public String getDocumentSubText(String tagBlock)
+       {
+               return getSubText(tagBlock);
+       }
+
+       /** Method for extracting the text within a tag
+         */
+       private String getSubText(String containingTag)
+       {
+               jtpSource.setText(jtpMain.getText());
+               String docTextCase = jtpSource.getText().toLowerCase();
+               int tagStart       = docTextCase.indexOf("<" + containingTag.toLowerCase());
+               int tagStartClose  = docTextCase.indexOf(">", tagStart) + 1;
+               String closeTag    = "</" + containingTag.toLowerCase() + ">";
+               int tagEndOpen     = docTextCase.indexOf(closeTag);
+               if(tagStartClose < 0) { tagStartClose = 0; }
+               if(tagEndOpen < 0 || tagEndOpen > docTextCase.length()) { tagEndOpen = docTextCase.length(); }
+               return jtpSource.getText().substring(tagStartClose, tagEndOpen);
+       }
+
+       /** Convenience method for obtaining the document text
+               * contained within the BODY tags (a common request)
+         */
+       public String getDocumentBody()
+       {
+               return getSubText("body");
+       }
+
+       /** Convenience method for setting the document text
+         */
+       public void setDocumentText(String sText)
+       {
+               jtpMain.setText(sText);
+               ((HTMLEditorKit)(jtpMain.getEditorKit())).setDefaultCursor(new Cursor(Cursor.TEXT_CURSOR));
+               jtpSource.setText(jtpMain.getText());
+               ((HTMLEditorKit)(jtpSource.getEditorKit())).setDefaultCursor(new Cursor(Cursor.TEXT_CURSOR));
+       }
+
+       /** Convenience method for obtaining the document text
+         */
+       private void updateTitle()
+       {
+               frameHandler.setTitle(appName + (currentFile == null ? "" : " - " + currentFile.getName()));
+       }
+
+       /** Convenience method for clearing out the UndoManager
+         */
+       public void purgeUndos()
+       {
+               if(undoMngr != null)
+               {
+                       undoMngr.discardAllEdits();
+                       undoAction.updateUndoState();
+                       redoAction.updateRedoState();
+               }
+       }
+
+       /** Convenience method for refreshing and displaying changes
+         */
+       public void refreshOnUpdate()
+       {
+               jtpMain.setText(jtpMain.getText());
+               jtpSource.setText(jtpMain.getText());
+               purgeUndos();
+               this.repaint();
+       }
+
+       /** Convenience method for deallocating the app resources
+         */
+       public void dispose()
+       {
+               frameHandler.dispose();
+               spellCheck.dispose();
+               spellCheck = null;
+               spellDialog = null;
+               System.exit(0);
+       }
+
+       /** Convenience method for fetching icon images from jar file
+         */
+       private ImageIcon getEkitIcon(String iconName)
+       {
+               return new ImageIcon(Toolkit.getDefaultToolkit().getImage(getClass().getResource("icons/" + iconName + "HK.gif")));
+       }
+
+       /** Convenience method for outputting exceptions
+         */
+       private void logException(String internalMessage, Exception e)
+       {
+               System.err.println(internalMessage);
+               e.printStackTrace(System.err);
+       }
+
+       /** Convenience method for toggling source window visibility
+         */
+       private void toggleSourceWindow()
+       {
+               if(!(jspSource.isShowing()))
+               {
+                       jtpSource.setText(jtpMain.getText());
+                       jspltDisplay.setRightComponent(jspSource);
+                       if(exclusiveEdit)
+                       {
+                               jspltDisplay.setDividerLocation(0);
+                               jspltDisplay.setEnabled(false);
+                       }
+                       else
+                       {
+                               jspltDisplay.setDividerLocation(iSplitPos);
+                               jspltDisplay.setEnabled(true);
+                       }
+               }
+               else
+               {
+                       jtpMain.setText(jtpSource.getText());
+                       iSplitPos = jspltDisplay.getDividerLocation();
+                       jspltDisplay.remove(jspSource);
+                       jtpMain.requestFocus();
+               }
+               this.validate();
+               jcbmiViewSource.setSelected(jspSource.isShowing());
+               jtbtnViewSource.setSelected(jspSource.isShowing());
+       }
+
+       /** Searches the specified element for CLASS attribute setting
+         */
+       private String findStyle(Element element)
+       {
+               AttributeSet as = element.getAttributes();
+               if(as == null)
+               {
+                       return null;
+               }
+               Object val = as.getAttribute(HTML.Attribute.CLASS);
+               if(val != null && (val instanceof String))
+               {
+                       return (String)val;
+               }
+               for(Enumeration e = as.getAttributeNames(); e.hasMoreElements();)
+               {
+                       Object key = e.nextElement();
+                       if(key instanceof HTML.Tag)
+                       {
+                               AttributeSet eas = (AttributeSet)(as.getAttribute(key));
+                               if(eas != null)
+                               {
+                                       val = eas.getAttribute(HTML.Attribute.CLASS);
+                                       if(val != null)
+                                       {
+                                               return (String)val;
+                                       }
+                               }
+                       }
+
+               }
+               return null;
+       }
+
+       /** Handles caret tracking and related events, such as displaying the current style
+         * of the text under the caret
+         */
+       private void handleCaretPositionChange(CaretEvent ce)
+       {
+               int caretPos = ce.getDot();
+               Element element = htmlDoc.getCharacterElement(caretPos);
+/*
+---- TAG EXPLICATOR CODE -------------------------------------------
+               javax.swing.text.ElementIterator ei = new javax.swing.text.ElementIterator(htmlDoc);
+               Element ele;
+               while((ele = ei.next()) != null)
+               {
+                       System.out.println("ELEMENT : " + ele.getName());
+               }
+               System.out.println("ELEMENT:" + element.getName());
+               Element elementParent = element.getParentElement();
+               System.out.println("ATTRS:");
+               AttributeSet attribs = elementParent.getAttributes();
+               for(Enumeration eAttrs = attribs.getAttributeNames(); eAttrs.hasMoreElements();)
+               {
+                       System.out.println("  " + eAttrs.nextElement().toString());
+               }
+               while(elementParent != null && !elementParent.getName().equals("body"))
+               {
+                       String parentName = elementParent.getName();
+                       System.out.println("PARENT:" + parentName);
+                       System.out.println("ATTRS:");
+                       attribs = elementParent.getAttributes();
+                       for(Enumeration eAttr = attribs.getAttributeNames(); eAttr.hasMoreElements();)
+                       {
+                               System.out.println("  " + eAttr.nextElement().toString());
+                       }
+                       elementParent = elementParent.getParentElement();
+               }
+---- END -------------------------------------------
+*/
+               if(element == null)
+               {
+                       return;
+               }
+               String style = null;
+               Vector vcStyles = new Vector();
+               while(element != null)
+               {
+                       if(style == null)
+                       {
+                               style = findStyle(element);
+                       }
+                       vcStyles.add(element);
+                       element = element.getParentElement();
+               }
+               int stylefound = -1;
+               if(style != null)
+               {
+                       for(int i = 0; i < jcmbStyleSelector.getItemCount(); i++)
+                       {
+                               String in = (String)(jcmbStyleSelector.getItemAt(i));
+                               if(in.equalsIgnoreCase(style))
+                               {
+                                       stylefound = i;
+                                       break;
+                               }
+                       }
+               }
+               if(stylefound > -1)
+               {
+                       Action ac = jcmbStyleSelector.getAction();
+                       ac.setEnabled(false);
+                       jcmbStyleSelector.setSelectedIndex(stylefound);
+                       ac.setEnabled(true);
+               }
+               else
+               {
+                       jcmbStyleSelector.setSelectedIndex(0);
+               }
+       }
+
+       /** Server-side image handling methods
+         */
+       protected void setServletURL(String url)
+       {
+               ServletURL = url;
+       }
+
+       protected void setImageDir(String sysDir)
+       {
+               ImageDir = sysDir;
+       }
+
+       public void setTreePilotSystemID(String theSystem)
+       {
+               TreePilotSystemID = theSystem;
+       }
+
+       /** Utility methods
+         */
+       public ExtendedHTMLDocument getExtendedHtmlDoc()
+       {
+               return (ExtendedHTMLDocument)htmlDoc;
+       }
+
+       public int getCaretPosition()
+       {
+               return jtpMain.getCaretPosition();
+       }
+
+       public void setCaretPosition(int newPositon)
+       {
+               boolean end = true;
+               do
+               {
+                       end = true;
+                       try
+                       {
+                               jtpMain.setCaretPosition(newPositon);
+                       }
+                       catch (IllegalArgumentException iae)
+                       {
+                               end = false;
+                               newPositon--;
+                       }
+               } while(!end && newPositon >= 0);
+       }
+
+/* Inner Classes --------------------------------------------- */
+
+       /** Class for implementing Undo as an autonomous action
+         */
+       class UndoAction extends AbstractAction
+       {
+               public UndoAction()
+               {
+                       super(Translatrix.getTranslationString("Undo"));
+                       setEnabled(false);
+               }
+
+               public void actionPerformed(ActionEvent e)
+               {
+                       try
+                       {
+                               undoMngr.undo();
+                       }
+                       catch(CannotUndoException ex)
+                       {
+                               ex.printStackTrace();
+                       }
+                       updateUndoState();
+                       redoAction.updateRedoState();
+               }
+
+               protected void updateUndoState()
+               {
+                       if(undoMngr.canUndo())
+                       {
+                               setEnabled(true);
+                               putValue(Action.NAME, undoMngr.getUndoPresentationName());
+                       }
+                       else
+                       {
+                               setEnabled(false);
+                               putValue(Action.NAME, Translatrix.getTranslationString("Undo"));
+                       }
+               }
+       }
+
+       /** Class for implementing Redo as an autonomous action
+         */
+       class RedoAction extends AbstractAction
+       {
+               public RedoAction()
+               {
+                       super(Translatrix.getTranslationString("Redo"));
+                       setEnabled(false);
+               }
+
+               public void actionPerformed(ActionEvent e)
+               {
+                       try
+                       {
+                               undoMngr.redo();
+                       }
+                       catch(CannotUndoException ex)
+                       {
+                               ex.printStackTrace();
+                       }
+                       updateRedoState();
+                       undoAction.updateUndoState();
+               }
+
+               protected void updateRedoState()
+               {
+                       if(undoMngr.canRedo())
+                       {
+                               setEnabled(true);
+                               putValue(Action.NAME, undoMngr.getRedoPresentationName());
+                       }
+                       else
+                       {
+                               setEnabled(false);
+                               putValue(Action.NAME, Translatrix.getTranslationString("Redo"));
+                       }
+               }
+       }
+
+       /** Class for implementing the Undo listener to handle the Undo and Redo actions
+         */
+       class CustomUndoableEditListener implements UndoableEditListener
+       {
+               public void undoableEditHappened(UndoableEditEvent uee)
+               {
+                       undoMngr.addEdit(uee.getEdit());
+                       undoAction.updateUndoState();
+                       redoAction.updateRedoState();
+               }
+       }
+
+}
diff --git a/ekit/com/hexidec/ekit/LanguageResources.properties b/ekit/com/hexidec/ekit/LanguageResources.properties
new file mode 100644 (file)
index 0000000..149e865
--- /dev/null
@@ -0,0 +1,169 @@
+File=File*
+New=New*
+NewDocument=New Document*
+OpenDocument=Open Document*
+OpenBase64Document=Open Base64 Document*
+OpenStyle=Open Stylesheet*
+SaveDocument=Save Document*
+Save=Save*
+SaveAs=Save As*
+SaveBody=Save Body*
+SaveRTF=Save RTF*
+SaveB64=Save Base64*
+Serialize=Serialize*
+ReadFromSer=Read From Ser*
+Exit=Exit*
+Edit=Edit*
+Cut=Cut*
+Copy=Copy*
+Paste=Paste*
+Undo=Undo*
+Redo=Redo*
+SelectAll=Select All*
+SelectParagraph=Select Paragraph*
+SelectLine=Select Line*
+SelectWord=Select Word*
+View=View*
+ViewToolbar=Toolbar*
+ViewSource=Source*
+EditMode=Edit Mode*
+Font=Font*
+FontBold=Bold*
+FontItalic=Italic*
+FontUnderline=Underline*
+FontStrike=Strike-through*
+FontSize=Size*
+FontSize1=Smallest*
+FontSize2=Smaller*
+FontSize3=Small*
+FontSize4=Regular*
+FontSize5=Large*
+FontSize6=Larger*
+FontSize7=Largest*
+FontMonospaced=Monospaced*
+FontSansserif=Sans-Serif*
+FontSerif=Serif*
+FontSelect=Select Font*
+FontDialogTitle=Select Font*
+FontSample=Font Sample*
+Color=Color*
+CustomColor=Custom*
+ColorAqua=Aqua*
+ColorBlack=Black*
+ColorBlue=Blue*
+ColorFuschia=Fuschia*
+ColorGray=Gray*
+ColorGreen=Green*
+ColorLime=Lime*
+ColorMaroon=Maroon*
+ColorNavy=Navy*
+ColorOlive=Olive*
+ColorPurple=Purple*
+ColorRed=Red*
+ColorSilver=Silver*
+ColorTeal=Teal*
+ColorWhite=White*
+ColorYellow=Yellow*
+Format=Format*
+FormatBig=Big*
+FormatSmall=Small*
+FontSuperscript=Superscript*
+FontSubscript=Subscript*
+Heading=Heading*
+Heading1=Heading 1*
+Heading2=Heading 2*
+Heading3=Heading 3*
+Heading4=Heading 4*
+Heading5=Heading 5*
+Heading6=Heading 6*
+ListUnordered=Unordered List*
+ListOrdered=Ordered List*
+ListItem=List Item*
+FormatBlockquote=Blockquote*
+FormatPre=Preformatted*
+FormatSpan=Span*
+FormatStrong=Strong*
+FormatEmphasis=Emphasis*
+FormatTT=Typewritten*
+FormatClear=Clear Format*
+Align=Align*
+AlignLeft=Align Left*
+AlignCenter=Align Center*
+AlignRight=Align Right*
+AlignJustified=Align Justified*
+Insert=Insert*
+InsertAnchor=Anchor*
+InsertBreak=Break*
+InsertHorizontalRule=Horizontal Rule*
+InsertLocalImage=Image From File*
+InsertServerImage=Image From Server*
+InsertNBSP=Nonbreaking Space*
+Table=Table*
+InsertTable=Create Table*
+InsertTableRow=Insert Row*
+InsertTableColumn=Insert Column*
+DeleteTableRow=Delete Row*
+DeleteTableColumn=Delete Column*
+Debug=Debug*
+DescribeDoc=Describe Doc*
+DescribeCSS=Describe CSS*
+WhatTags=What Tags?*
+ToolAnchor=Insert Anchor*
+AnchorDialogTitle=Anchor Reference*
+ImageDialogTitle=Select Image To Insert*
+TableDialogTitle=Table Properties*
+DialogAccept=Accept*
+DialogCancel=Cancel*
+DialogClose=Close*
+TableRows=Table Rows*
+TableColumns=Table Columns*
+TableBorder=Border Width*
+TableCellSpacing=Cell Spacing*
+TableCellPadding=Cell Padding*
+UndoError=Unable to undo*
+RedoError=Unable to redo*
+Help=Help*
+About=About*
+AboutMessage=Ekit (c)2000-2003 Howard Kistler\nhexidec codex\nwww.hexidec.com
+Index=Index*
+Contents=Contents*
+Search=Search*
+SearchFind=Find*
+SearchFindAgain=Find Again*
+SearchReplace=Replace*
+SearchDialogTitle=Search*
+SearchCaseSensitive=Case Sensitive*
+SearchStartAtTop=Start At Top*
+SearchReplaceAll=Replace All*
+Forms=Forms*
+FormInsertForm=Insert Form*
+FormTextfield=Text Field*
+FormTextarea=Text Area*
+FormCheckbox=Checkbox*
+FormRadio=Radio Button*
+FormPassword=Password*
+FormButton=Button*
+FormButtonSubmit=Submit Button*
+FormButtonReset=Reset Button*
+FormDialogTitle=Properties For Form Element*
+Tools=Tools*
+ToolSpellcheck=Spellchecker*
+ToolSpellcheckDialog=Check Spelling*
+FiletypeHTML=HTML Files*
+FiletypeCSS=CSS Files*
+FiletypeRTF=RTF Files*
+FiletypeB64=Base64 Files*
+FiletypeSer=Serialized Files*
+FiletypeIMG=Images*
+NoCSSStyle=(none)*
+Error=Error*
+ErrorNoTextSelected=No text was selected.*
+ErrorNoOccurencesFound=No occurrences found*
+ErrorNoMatchFound=No match found*
+ErrorCannotConvertToList=Cannot convert the selected text to a list.*
+ErrorNestedListsNotSupported=Lists cannot be created inside other lists.*
+ErrorRuntimeException=Runtime Exception occurred.*
+ErrorIOException=IO Exception occurred.*
+ErrorBadLocationException=Bad Location Exception occurred.*
+AskNewDocument=Create new blank document?*
+DictionaryFile=english
\ No newline at end of file
diff --git a/ekit/com/hexidec/ekit/LanguageResources_de_DE.properties b/ekit/com/hexidec/ekit/LanguageResources_de_DE.properties
new file mode 100644 (file)
index 0000000..c84d1ce
--- /dev/null
@@ -0,0 +1,121 @@
+File=Datei
+New=Neu
+NewDocument=Datei neu
+OpenDocument=Datei öffnen
+OpenStyle=Formatvorlage öffnen
+SaveDocument=Datei speichern
+Save=Speichern
+SaveAs=Speichern als
+SaveBody=Body speichern
+SaveRTF=Speichern RTF
+Serialize=Serialisieren
+ReadFromSer=Serialisierte Datei lesen
+Exit=Beenden
+Edit=Bearbeiten
+Cut=Ausschneiden
+Copy=Kopieren
+Paste=Einfügen
+Undo=Rückgängig
+Redo=Wiederholen
+SelectAll=Alles markieren
+SelectParagraph=Absatz markieren
+SelectLine=Zeile markieren
+SelectWord=Wort markieren
+View=Ansicht
+ViewToolbar=Symbolleisten
+ViewSource=Quelltext
+EditMode=Bearbeiten Modus
+Font=Schriftart
+FontBold=Fett
+FontItalic=Kursiv
+FontUnderline=Unterstrichen
+FontMonospaced=Nicht Proportional
+FontSansserif=Serifenlos
+FontSerif=Mit Serifen
+Color=Farbe
+ColorAqua=Cyan
+ColorBlack=Schwarz
+ColorBlue=Blau
+ColorFuschia=Fuschia
+ColorGray=Grau
+ColorGreen=Grün
+ColorLime=Lime
+ColorMaroon=Maroon
+ColorNavy=Marine
+ColorOlive=Olive
+ColorPurple=Veilchen
+ColorRed=Rot
+ColorSilver=Silber
+ColorTeal=Teal
+ColorWhite=Weiß
+ColorYellow=Gelb
+Format=Format
+FormatBig=Groß
+FormatSmall=Klein
+FontSuperscript=Hochgestellt
+FontSubscript=Tiefgestellt
+Heading=Überschrift
+Heading1=Überschrift 1
+Heading2=Überschrift 2
+Heading3=Überschrift 3
+Heading4=Überschrift 4
+Heading5=Überschrift 5
+Heading6=Überschrift 6
+ListUnordered=Ungeordnete Liste
+ListOrdered=Geordnete Liste
+ListItem=Listeneintrag
+ListUnorderedItem=Einfügen Ungeordnete Listeneintrag
+ListOrderedItem=Einfügen Geordnete Listeneintrag
+FormatSpan=Span
+FormatClear=Formatierungen aufheben
+Align=Ausrichtung
+AlignLeft=Ausrichtung Links
+AlignCenter=Ausrichtung Mitte
+AlignRight=Ausrichtung Rechts
+AlignJustified=Blocksatz
+Insert=Einfügen
+InsertAnchor=Anker
+InsertBreak=Zeilenumbruch
+InsertHorizontalRule=Waagerechte Linie
+InsertLocalImage=Bild
+InsertTable=Tabelle
+InsertTableRow=Tabellenreihe
+InsertTableCell=Tabellenzelle
+Debug=Debug
+DescribeDoc=Beschreibe Dokument
+DescribeCSS=Beschreibe CSS
+WhatTags=Welche Tags?
+ToolAnchor=Anker einfügen
+AnchorDialogTitle=Anker Bezug
+TableDialogTitle=Tabelleneigenschaften
+DialogAccept=Akzeptieren
+DialogCancel=Abbrechen
+TableRows=Tabellenzeilen
+TableColumns=Tabellenspalten
+TableBorder=Rahmenbreite
+DialogAccept=Bestätigen
+DialogCancel=Annullieren
+DialogClose=Entlass
+UndoError=Rückgängig nicht möglich
+RedoError=Wiederholen nicht möglich
+Help=Hilfe
+About=Informationen
+Index=Index
+Contents=Inhalt
+Search=Suchen
+SearchFind=Finden
+SearchFindAgain=Finden Wieder
+SearchReplace=Ersetzen
+SearchDialogTitle=Suchen
+SearchStartAtTop=Anfang Oben
+SearchReplaceAll=Ersetzen Sie Alle
+FiletypeHTML=HTML Akten
+FiletypeCSS=CSS Akten
+FiletypeRTF=RTF Akten
+FiletypeSer=Serialisierte Akten
+FiletypeIMG=Abbildungen
+NoCSSStyle=(keine)
+ErrorNoTextSelected=Kein Text wurde auserwählt.
+ErrorNoOccurencesFound=Keine Vorkommen fanden
+ErrorNoMatchFound=Kein zusammenpassender Text gefunden
+ErrorCannotConvertToList=Kann nicht den auserwählten Text in eine Liste umwandeln.
diff --git a/ekit/com/hexidec/ekit/LanguageResources_en_UK.properties b/ekit/com/hexidec/ekit/LanguageResources_en_UK.properties
new file mode 100644 (file)
index 0000000..60fa3d4
--- /dev/null
@@ -0,0 +1,169 @@
+File=File
+New=New
+NewDocument=New Document
+OpenDocument=Open Document
+OpenBase64Document=Open Base64 Document
+OpenStyle=Open Stylesheet
+SaveDocument=Save Document
+Save=Save
+SaveAs=Save As
+SaveBody=Save Body
+SaveRTF=Save RTF
+SaveB64=Save Base64
+Serialize=Serialise
+ReadFromSer=Read From Ser
+Exit=Exit
+Edit=Edit
+Cut=Cut
+Copy=Copy
+Paste=Paste
+Undo=Undo
+Redo=Redo
+SelectAll=Select All
+SelectParagraph=Select Paragraph
+SelectLine=Select Line
+SelectWord=Select Word
+View=View
+ViewToolbar=Toolbar
+ViewSource=Source
+EditMode=Edit Mode
+Font=Font
+FontBold=Bold
+FontItalic=Italic
+FontUnderline=Underline
+FontStrike=Strike-through
+FontSize=Size
+FontSize1=Smallest
+FontSize2=Smaller
+FontSize3=Small
+FontSize4=Regular
+FontSize5=Large
+FontSize6=Larger
+FontSize7=Largest
+FontMonospaced=Monospaced
+FontSansserif=Sans-Serif
+FontSerif=Serif
+FontSuperscript=Superscript
+FontSubscript=Subscript
+FontSelect=Select Font
+FontDialogTitle=Select Font
+FontSample=Font Sample
+Color=Colour
+CustomColor=Custom
+ColorAqua=Aqua
+ColorBlack=Black
+ColorBlue=Blue
+ColorFuschia=Fuschia
+ColorGray=Grey
+ColorGreen=Green
+ColorLime=Lime
+ColorMaroon=Maroon
+ColorNavy=Navy
+ColorOlive=Olive
+ColorPurple=Purple
+ColorRed=Red
+ColorSilver=Silver
+ColorTeal=Teal
+ColorWhite=White
+ColorYellow=Yellow
+Format=Format
+FormatBig=Big
+FormatSmall=Small
+FormatSpan=Span
+FormatBlockquote=Blockquote
+FormatPre=Preformatted
+FormatStrong=Strong
+FormatEmphasis=Emphasis
+FormatTT=Typewritten
+FormatClear=Clear Format
+Heading=Heading
+Heading1=Heading 1
+Heading2=Heading 2
+Heading3=Heading 3
+Heading4=Heading 4
+Heading5=Heading 5
+Heading6=Heading 6
+ListUnordered=Unordered List
+ListOrdered=Ordered List
+ListItem=List Item
+Align=Align
+AlignLeft=Align Left
+AlignCenter=Align Center
+AlignRight=Align Right
+AlignJustified=Align Justified
+Insert=Insert
+InsertAnchor=Anchor
+InsertBreak=Break
+InsertHorizontalRule=Horizontal Rule
+InsertLocalImage=Image From File
+InsertServerImage=Image From Server
+InsertNBSP=Nonbreaking Space
+Table=Table
+InsertTable=Create Table
+InsertTableRow=Insert Row
+InsertTableColumn=Insert Column
+DeleteTableRow=Delete Row
+DeleteTableColumn=Delete Column
+Debug=Debug
+DescribeDoc=Describe Doc
+DescribeCSS=Describe CSS
+WhatTags=What Tags?
+ToolAnchor=Insert Anchor
+AnchorDialogTitle=Anchor Reference
+ImageDialogTitle=Select Image To Insert
+TableDialogTitle=Table Properties
+DialogAccept=Accept
+DialogCancel=Cancel
+DialogClose=Close
+TableRows=Table Rows
+TableColumns=Table Columns
+TableBorder=Border Width
+TableCellSpacing=Cell Spacing
+TableCellPadding=Cell Padding
+UndoError=Unable to undo
+RedoError=Unable to redo
+Help=Help
+About=About
+AboutMessage=Ekit (c)2000-2003 Howard Kistler\nhexidec codex\nwww.hexidec.com
+Index=Index
+Contents=Contents
+Search=Search
+SearchFind=Find
+SearchFindAgain=Find Again
+SearchReplace=Replace
+SearchDialogTitle=Search
+SearchCaseSensitive=Case Sensitive
+SearchStartAtTop=Start At Top
+SearchReplaceAll=Replace All
+Forms=Forms
+FormInsertForm=Insert Form
+FormTextfield=Text Field
+FormTextarea=Text Area
+FormCheckbox=Checkbox
+FormRadio=Radio Button
+FormPassword=Password
+FormButton=Button
+FormButtonSubmit=Submit Button
+FormButtonReset=Reset Button
+FormDialogTitle=Properties For Form Element
+Tools=Tools
+ToolSpellcheck=Spellchecker
+ToolSpellcheckDialog=Check Spelling
+FiletypeHTML=HTML Files
+FiletypeCSS=CSS Files
+FiletypeRTF=RTF Files
+FiletypeB64=Base64 Files
+FiletypeSer=Serialised Files
+FiletypeIMG=Images
+NoCSSStyle=(none)
+Error=Error
+ErrorNoTextSelected=No text was selected.
+ErrorNoOccurencesFound=No occurrences found
+ErrorNoMatchFound=No match found
+ErrorCannotConvertToList=Cannot convert the selected text to a list.
+ErrorNestedListsNotSupported=Lists cannot be created inside other lists.
+ErrorRuntimeException=Runtime Exception occurred.
+ErrorIOException=IO Exception occurred.
+ErrorBadLocationException=Bad Location Exception occurred.
+AskNewDocument=Create new blank document?
+DictionaryFile=english
\ No newline at end of file
diff --git a/ekit/com/hexidec/ekit/LanguageResources_en_US.properties b/ekit/com/hexidec/ekit/LanguageResources_en_US.properties
new file mode 100644 (file)
index 0000000..48a4a4c
--- /dev/null
@@ -0,0 +1,169 @@
+File=File
+New=New
+NewDocument=New Document
+OpenDocument=Open Document
+OpenBase64Document=Open Base64 Document
+OpenStyle=Open Stylesheet
+SaveDocument=Save Document
+Save=Save
+SaveAs=Save As
+SaveBody=Save Body
+SaveRTF=Save RTF
+SaveB64=Save Base64
+Serialize=Serialize
+ReadFromSer=Read From Ser
+Exit=Exit
+Edit=Edit
+Cut=Cut
+Copy=Copy
+Paste=Paste
+Undo=Undo
+Redo=Redo
+SelectAll=Select All
+SelectParagraph=Select Paragraph
+SelectLine=Select Line
+SelectWord=Select Word
+View=View
+ViewToolbar=Toolbar
+ViewSource=Source
+EditMode=Edit Mode
+Font=Font
+FontBold=Bold
+FontItalic=Italic
+FontUnderline=Underline
+FontStrike=Strike-through
+FontSize=Size
+FontSize1=Smallest
+FontSize2=Smaller
+FontSize3=Small
+FontSize4=Regular
+FontSize5=Large
+FontSize6=Larger
+FontSize7=Largest
+FontMonospaced=Monospaced
+FontSansserif=Sans-Serif
+FontSerif=Serif
+FontSuperscript=Superscript
+FontSubscript=Subscript
+FontSelect=Select Font
+FontDialogTitle=Select Font
+FontSample=Font Sample
+Color=Color
+CustomColor=Custom
+ColorAqua=Aqua
+ColorBlack=Black
+ColorBlue=Blue
+ColorFuschia=Fuschia
+ColorGray=Gray
+ColorGreen=Green
+ColorLime=Lime
+ColorMaroon=Maroon
+ColorNavy=Navy
+ColorOlive=Olive
+ColorPurple=Purple
+ColorRed=Red
+ColorSilver=Silver
+ColorTeal=Teal
+ColorWhite=White
+ColorYellow=Yellow
+Format=Format
+FormatBig=Big
+FormatSmall=Small
+FormatSpan=Span
+FormatBlockquote=Blockquote
+FormatPre=Preformatted
+FormatStrong=Strong
+FormatEmphasis=Emphasis
+FormatTT=Typewritten
+FormatClear=Clear Format
+Heading=Heading
+Heading1=Heading 1
+Heading2=Heading 2
+Heading3=Heading 3
+Heading4=Heading 4
+Heading5=Heading 5
+Heading6=Heading 6
+ListUnordered=Unordered List
+ListOrdered=Ordered List
+ListItem=List Item
+Align=Align
+AlignLeft=Align Left
+AlignCenter=Align Center
+AlignRight=Align Right
+AlignJustified=Align Justified
+Insert=Insert
+InsertAnchor=Anchor
+InsertBreak=Break
+InsertHorizontalRule=Horizontal Rule
+InsertLocalImage=Image From File
+InsertServerImage=Image From Server
+InsertNBSP=Nonbreaking Space
+Table=Table
+InsertTable=Create Table
+InsertTableRow=Insert Row
+InsertTableColumn=Insert Column
+DeleteTableRow=Delete Row
+DeleteTableColumn=Delete Column
+Debug=Debug
+DescribeDoc=Describe Doc
+DescribeCSS=Describe CSS
+WhatTags=What Tags?
+ToolAnchor=Insert Anchor
+AnchorDialogTitle=Anchor Reference
+ImageDialogTitle=Select Image To Insert
+TableDialogTitle=Table Properties
+DialogAccept=Accept
+DialogCancel=Cancel
+DialogClose=Close
+TableRows=Table Rows
+TableColumns=Table Columns
+TableBorder=Border Width
+TableCellSpacing=Cell Spacing
+TableCellPadding=Cell Padding
+UndoError=Unable to undo
+RedoError=Unable to redo
+Help=Help
+About=About
+AboutMessage=Ekit (c)2000-2003 Howard Kistler\nhexidec codex\nwww.hexidec.com
+Index=Index
+Contents=Contents
+Search=Search
+SearchFind=Find
+SearchFindAgain=Find Again
+SearchReplace=Replace
+SearchDialogTitle=Search
+SearchCaseSensitive=Case Sensitive
+SearchStartAtTop=Start At Top
+SearchReplaceAll=Replace All
+Forms=Forms
+FormInsertForm=Insert Form
+FormTextfield=Text Field
+FormTextarea=Text Area
+FormCheckbox=Checkbox
+FormRadio=Radio Button
+FormPassword=Password
+FormButton=Button
+FormButtonSubmit=Submit Button
+FormButtonReset=Reset Button
+FormDialogTitle=Properties For Form Element
+Tools=Tools
+ToolSpellcheck=Spellchecker
+ToolSpellcheckDialog=Check Spelling
+FiletypeHTML=HTML Files
+FiletypeCSS=CSS Files
+FiletypeRTF=RTF Files
+FiletypeB64=Base64 Files
+FiletypeSer=Serialized Files
+FiletypeIMG=Images
+NoCSSStyle=(none)
+Error=Error
+ErrorNoTextSelected=No text was selected.
+ErrorNoOccurencesFound=No occurrences found
+ErrorNoMatchFound=No match found
+ErrorCannotConvertToList=Cannot convert the selected text to a list.
+ErrorNestedListsNotSupported=Lists cannot be created inside other lists.
+ErrorRuntimeException=Runtime Exception occurred.
+ErrorIOException=IO Exception occurred.
+ErrorBadLocationException=Bad Location Exception occurred.
+AskNewDocument=Create new blank document?
+DictionaryFile=english
\ No newline at end of file
diff --git a/ekit/com/hexidec/ekit/LanguageResources_es_ES.properties b/ekit/com/hexidec/ekit/LanguageResources_es_ES.properties
new file mode 100644 (file)
index 0000000..6c830bf
--- /dev/null
@@ -0,0 +1,126 @@
+File=Archivo
+New=Nuevo
+NewDocument=Nuevo Documento
+OpenDocument=Abrir Documento
+OpenBase64Document=Abrir Documento Base64
+OpenStyle=Abrir Hoja de Estilo
+SaveDocument=Guardar Documento
+Save=Guardar
+SaveAs=Guardar como
+SaveBody=Guardar Contenido
+SaveRTF=Guardar RTF
+SaveB64=Guardar Base64
+Serialize=Serializar
+ReadFromSer=Importar Serializado
+Exit=Salir
+Edit=Editar
+Cut=Cortar
+Copy=Copiar
+Paste=Pegar
+Undo=Deshacer
+Redo=Rehacer
+SelectAll=Seleccionar Todo
+SelectParagraph=Seleccionar Párrafo
+SelectLine=Seleccionar Línea
+SelectWord=Seleccionar Palabra
+View=Ver
+ViewToolbar=Barra de herramientas
+ViewSource=Ver Código Fuente
+EditMode=Modo de Edición
+Font=Fuente
+FontBold=Negrita
+FontItalic=Cursiva
+FontUnderline=Subrayado
+FontSize=Size
+FontSize1=Muy Pequeño
+FontSize2=Más Pequeño
+FontSize3=Pequeño
+FontSize4=Normal
+FontSize5=Grande
+FontSize6=Más Grande
+FontSize7=Muy Grande
+FontMonospaced=Monoespaciada
+FontSansserif=Sans-Serif
+FontSerif=Serif
+FontSuperscript=Superíndice
+FontSubscript=Subíndice
+Color=Color
+ColorAqua=Ciánico
+ColorBlack=Negro
+ColorBlue=Azul
+ColorFuschia=Fuschia
+ColorGray=Gris
+ColorGreen=Verde
+ColorLime=Lime
+ColorMaroon=Escarlata
+ColorNavy=Marina
+ColorOlive=Aceituna
+ColorPurple=Púrpura
+ColorRed=Rojo
+ColorSilver=Plata
+ColorTeal=Teal
+ColorWhite=Blanco
+ColorYellow=Amarillo
+Format=Formato
+FormatBig=Grande
+FormatSmall=Pequeño
+Heading=Encabezado
+Heading1=Encabezado 1
+Heading2=Encabezado 2
+Heading3=Encabezado 3
+Heading4=Encabezado 4
+Heading5=Encabezado 5
+Heading6=Encabezado 6
+ListUnordered=Lista No ordenada
+ListOrdered=Lista Ordenada
+ListItem=Elemento Lista
+ListUnorderedItem=Insertar Elemento No ordenada
+ListOrderedItem=Insertar Elemento Ordenada
+FormatSpan=Agrupar(Span)
+FormatClear=Eliminar Formato
+Align=Alinear
+AlignLeft=Alinear a la Izquierda
+AlignCenter=Centrar
+AlignRight=Alinear a la Derecha
+AlignJustified=Justificar
+Insert=Insertar
+InsertAnchor=Enlace
+InsertBreak=Salto de Línea
+InsertHorizontalRule=Línea Horizontal
+InsertLocalImage=Imagen
+InsertTable=Tabla
+InsertTableRow=Fila Tabla
+InsertTableColumn=Columna Tabla
+InsertTableCell=Celda Tabla
+Debug=Depurar
+DescribeDoc=Describir Doc
+DescribeCSS=Describir CSS
+WhatTags=¿Qué Etiquetas?
+ToolAnchor=Insertar Enlace(Link)
+AnchorDialogTitle=Destino del Enlace(Link)
+TableDialogTitle=Propiedades de la Tabla
+DialogAccept=Aceptar
+DialogCancel=Cancelar
+DialogClose=Cierren
+TableRows=Filas de la Tabla
+TableColumns=Columnas de la Tabla
+TableBorder=Anchura del Borde
+UndoError=Imposible deshacer
+RedoError=Imposible rehacer
+Help=Ayuda
+About=Información
+Index=Índice
+Contents=Contenido
+Search=Búsqueda
+SearchFind=Hallazgo
+SearchFindAgain=Hallazgo Otra Vez
+SearchReplace=Substituye
+SearchDialogTitle=Búsqueda
+SearchStartAtTop=Comienzo En La Parte Superior
+SearchReplaceAll=Substituye Todos
+FiletypeHTML=Archivos del HTML
+FiletypeCSS=Archivos del CSS
+FiletypeRTF=Archivos del RTF
+FiletypeSer=Archivos del Serializado
+FiletypeIMG=Cuadros
+NoCSSStyle=(ningunos)
diff --git a/ekit/com/hexidec/ekit/LanguageResources_es_MX.properties b/ekit/com/hexidec/ekit/LanguageResources_es_MX.properties
new file mode 100644 (file)
index 0000000..ce6c9c1
--- /dev/null
@@ -0,0 +1,125 @@
+File=Archivo
+New=Nuevo
+NewDocument=Nuevo Documento
+OpenDocument=Abrir Documento
+OpenStyle=Abrir Hoja de Estilo
+SaveDocument=Guardar Documento
+Save=Guardar
+SaveAs=Guardar como
+SaveBody=Guardar Contenido
+SaveRTF=Guardar RTF
+Serialize=Serializar
+ReadFromSer=Importar Serializado
+Exit=Salir
+Edit=Editar
+Cut=Cortar
+Copy=Copiar
+Paste=Pegar
+Undo=Deshacer
+Redo=Rehacer
+SelectAll=Seleccionar Todo
+SelectParagraph=Seleccionar Párrafo
+SelectLine=Seleccionar Línea
+SelectWord=Seleccionar Palabra
+View=Ver
+ViewToolbar=Barra de herramientas
+ViewSource=Ver Código Fuente
+EditMode=Modo de Edición
+Font=Fuente
+FontBold=Negrita
+FontItalic=Cursiva
+FontUnderline=Subrayado
+FontStrike=Tachado
+FontMonospaced=Mono-Espaciada
+FontSansserif=Sans-Serif
+FontSerif=Serif
+FontSelect=Seleccionar Fuente
+Color=Color
+ColorAqua=Ciánico
+ColorBlack=Negro
+ColorBlue=Azul
+ColorFuschia=Fuschia
+ColorGray=Gris
+ColorGreen=Verde
+ColorLime=Verde Limon
+ColorMaroon=Escarlata
+ColorNavy=Marina
+ColorOlive=Aceituna
+ColorPurple=Púrpura
+ColorRed=Rojo
+ColorSilver=Plata
+ColorTeal=Teal
+ColorWhite=Blanco
+ColorYellow=Amarillo
+Format=Formato
+FormatBig=Grande
+FormatSmall=Pequeño
+FontSuperscript=Superíndice
+FontSubscript=Subíndice
+Heading=Encabezado
+Heading1=Encabezado 1
+Heading2=Encabezado 2
+Heading3=Encabezado 3
+Heading4=Encabezado 4
+Heading5=Encabezado 5
+Heading6=Encabezado 6
+ListUnordered=Lista No ordenada
+ListOrdered=Lista Ordenada
+ListItem=Elemento Lista
+ListUnorderedItem=Insertar Elemento No ordenada
+ListOrderedItem=Insertar Elemento Ordenada
+FormatSpan=Agrupar(Span)
+FormatClear=Eliminar Formato
+Align=Alinear
+AlignLeft=Alinear a la Izquierda
+AlignCenter=Centrar
+AlignRight=Alinear a la Derecha
+AlignJustified=Justificar
+Insert=Insertar
+InsertAnchor=Liga
+InsertBreak=Salto de Línea
+InsertNBSP=Espacio blanco HTML (&nbsp;)
+InsertHorizontalRule=Línea Horizontal
+InsertImage=Imagen
+InsertTable=Tabla
+InsertTableRow=Fila Tabla
+InsertTableCell=Celda Tabla
+Debug=Depurar
+DescribeDoc=Describir Doc
+DescribeCSS=Describir CSS
+WhatTags=¿Qué Etiquetas?
+ToolAnchor=Insertar Enlace(Link)
+AnchorDialogTitle=Destino del Enlace(Link)
+TableDialogTitle=Propiedades de la Tabla
+DialogAccept=Aceptar
+DialogCancel=Cancelar
+DialogClose=Cerrar
+TableRows=Filas de la Tabla
+TableColumns=Columnas de la Tabla
+TableBorder=Anchura del Borde
+UndoError=Imposible deshacer
+RedoError=Imposible rehacer
+Help=Ayuda
+About=Información
+Index=Índice
+ImageDialogTitle=Seleccione la Imagen a insertar.
+Contents=Contenido
+Search=Búsqueda
+SearchFind=Buscar
+SearchCaseSensitive=Coincidir mayúsculas y minusculas
+SearchFindAgain=Buscar Otra Vez
+SearchReplace=Remplaza
+SearchDialogTitle=Búsqueda
+SearchStartAtTop=Comenzar en La Parte Superior
+SearchReplaceAll=Substituye Todos
+FiletypeHTML=Archivos del HTML
+FiletypeCSS=Archivos del CSS
+FiletypeRTF=Archivos del RTF
+FiletypeSer=Archivos del Serializado
+FiletypeIMG=Cuadros
+NoCSSStyle=(ningunos)
+ErrorNoTextSelected=No se seleccionó texto alguno.
+ErrorNoOccurencesFound=No se encontraró ocurrencias.
+ErrorNoMatchFound=No se encontró.
+TableDialogTitle=Propiedades de la Tabla
+
diff --git a/ekit/com/hexidec/ekit/LanguageResources_fi_FI.properties b/ekit/com/hexidec/ekit/LanguageResources_fi_FI.properties
new file mode 100644 (file)
index 0000000..8885250
--- /dev/null
@@ -0,0 +1,120 @@
+File=Tiedosto
+New=Uusi
+NewDocument=Uusi tiedosto
+OpenDocument=Avaa tiedosto
+OpenStyle=Avaa Stylesheet
+SaveDocument=Tallenna tiedosto
+Save=Tallenna
+SaveAs=Tallenna nimellä
+SaveBody=Tallenna Body
+SaveRTF=Tallenna RTF
+Serialize=Sarjoita   
+ReadFromSer=Lue sarjoitettu
+Exit=Poistu
+Edit=Muokkaa
+Cut=Leikkaa
+Copy=Kopioi
+Paste=Liimaa
+Undo=Kumoa
+Redo=Tee uudelleen
+SelectAll=Valitse kaikki
+SelectParagraph=Valitse kappale
+SelectLine=Valitse rivi
+SelectWord=Valitse sana
+View=Näytä
+ViewToolbar=Työkalut
+ViewSource=Lähdekoodi
+EditMode=Muokkaustila
+Font=Fontti
+FontBold=Lihavoitu
+FontItalic=Kursiivi
+FontUnderline=Alleviivattu
+FontMonospaced=Fontti 'Monospaced'
+FontSansserif=Fontti 'Sans-Serif'
+FontSerif=Fontti 'Serif'
+Color=Värit
+ColorAqua=Aqua
+ColorBlack=Musta
+ColorBlue=Sininen
+ColorFuschia=Fuschia
+ColorGray=Harmaa
+ColorGreen=Vihreä
+ColorLime=Lime
+ColorMaroon=Maroon
+ColorNavy=Sininen (Navy)
+ColorOlive=Oliivi
+ColorPurple=Purppura
+ColorRed=Punainen
+ColorSilver=Hopea
+ColorTeal=Teal
+ColorWhite=Valkoinen
+ColorYellow=Keltainen
+Format=Muotoilu
+FormatBig=Iso
+FormatSmall=Pieni
+FontSuperscript=Ylätunniste
+FontSubscript=Alatunniste
+FormatBlockquote=Lainaus
+FormatPre=Esimuotoiltu
+Heading=Otsikko
+Heading1=Otsikko 1 (suurin)
+Heading2=Otsikko 2
+Heading3=Otsikko 3
+Heading4=Otsikko 4
+Heading5=Otsikko 5
+Heading6=Otsikko 6 (pienin)
+ListUnordered=Lista
+ListOrdered=Numeroitu lista
+ListItem=Listan rivi
+FormatSpan=Solunvaihto (Span)
+FormatClear=Poista muotoilu
+Align=Tasaus
+AlignLeft=Tasaa vasenpaan
+AlignCenter=Tasaa keskelle
+AlignRight=Tasaa oikealle
+AlignJustified=Tasaa molemmat
+Insert=Lisää
+InsertAnchor=Ankkuroi
+InsertBreak=Vaihto
+InsertHorizontalRule=Vaakaviiva
+InsertLocalImage=Kuva
+InsertTable=Taulukko
+InsertTableRow=Taulukon rivi
+InsertTableCell=Taulukon solu
+Debug=Debug
+DescribeDoc=Tiedoston kuvaus
+DescribeCSS=CSS:n kuvaus
+WhatTags=Mitkä tagit?
+ToolAnchor=Lisää ankkurointi
+AnchorDialogTitle=Ankkuroinnin nimi
+TableDialogTitle=Taulun nimi
+DialogAccept=Hyväksy
+DialogCancel=Peruuta
+DialogClose=Sulje
+TableRows=Taulukon Rivit
+TableColumns=Taulukon Sarakkeet
+TableBorder=Reunan leveys
+UndoError=Kumoaminen ei onnistunut
+RedoError=Uudelleen tekeminen ei onnistunut
+Help=Avut
+About=Tietoja
+Index=Aihehakemisto
+Contents=Sisältö
+Search=Haku
+SearchFind=Haku
+SearchFindAgain=Hae uudelleen
+SearchReplace=Korvaa
+SearchDialogTitle=Haku
+SearchCaseSensitive=Muotoilun mukaan
+SearchStartAtTop=Aloita alusta
+SearchReplaceAll=Korvaa kaikki
+FiletypeHTML=HTML tiedostot
+FiletypeCSS=CSS tiedostot
+FiletypeRTF=RTF tiedostot
+FiletypeSer=Sarjoitetuttiedostot
+FiletypeIMG=Kuvat
+NoCSSStyle=(ei muotilua)
+ErrorNoTextSelected=Tekstiä ei valittu
+ErrorNoOccurencesFound=Haettavaa ei löytynyt
+ErrorNoMatchFound=Hakua vastaavaa ei löytynyt
+ErrorCannotConvertToList=Valittua tekstiä ei voi muuntaa listaksi
diff --git a/ekit/com/hexidec/ekit/LanguageResources_fr_FR.properties b/ekit/com/hexidec/ekit/LanguageResources_fr_FR.properties
new file mode 100644 (file)
index 0000000..0b8af22
--- /dev/null
@@ -0,0 +1,116 @@
+File=Fichier
+New=Nouveau
+NewDocument=Nouveau Document
+OpenDocument=Ouvrir le Document
+OpenStyle=Ouvrez une Feuille de Style
+SaveDocument=Sauvegarder le Document
+Save=Enregistrer
+SaveAs=Enregistrer Sous
+SaveBody=Enregistrer Le Corps
+SaveRTF=Enregistrer en RTF
+Serialize=Serialize
+ReadFromSer=Lire de Serialize
+Exit=Quitter
+Edit=Editer
+Cut=Couper
+Copy=Copier
+Paste=Coller
+Undo=Défaire
+Redo=Refaire
+SelectAll=Sélectionner Tout
+SelectParagraph=Sélectionner Le Paragraphe
+SelectLine=Sélectionner La Ligne
+SelectWord=Sélectionner Le Mot
+View=Affichage
+ViewToolbar=Barre d'outils
+ViewSource=Code Source
+EditMode=Mode Edition
+Font=Police
+FontBold=Gras
+FontItalic=Italique
+FontUnderline=Souligner
+FontMonospaced=Monospace
+FontSansserif=Sans-Serif
+FontSerif=Serif
+Color=Couleur
+ColorAqua=Cyan
+ColorBlack=Noir
+ColorBlue=Bleu
+ColorFuschia=Fuschia
+ColorGray=Gris
+ColorGreen=Vert
+ColorLime=Lime
+ColorMaroon=Écarlate
+ColorNavy=Marine
+ColorOlive=Olive
+ColorPurple=Pourpre
+ColorRed=Rouge
+ColorSilver=Argent
+ColorTeal=Teal
+ColorWhite=Blanc
+ColorYellow=Jaune
+Format=Format
+FormatBig=Grand
+FormatSmall=Petit
+FontSuperscript=Indice supérieur
+FontSubscript=Indice inférieur
+Heading=Entête
+Heading1=Entête 1
+Heading2=Entête 2
+Heading3=Entête 3
+Heading4=Entête 4
+Heading5=Entête 5
+Heading6=Entête 6
+ListUnordered=Liste Non Ordonnée
+ListOrdered=Liste Ordonnée
+ListItem=Article d'une Liste
+ListUnorderedItem=Insertion Article Non Ordonnée
+ListOrderedItem=Insertion Article Ordonnée
+FormatSpan=balise Span
+FormatClear=Supprimer Format
+Align=Aligner
+AlignLeft=Aligner à Gauche
+AlignCenter=Centrer
+AlignRight=Aligner à Droite
+AlignJustified=Justifié
+Insert=Insertion
+InsertAnchor=Ancre
+InsertBreak=Coupure
+InsertHorizontalRule=Ligne Horizontale
+InsertLocalImage=Image
+InsertTable=Tableau
+InsertTableRow=Rangée du Tableau
+InsertTableCell=Cellule du Tableau
+Debug=Deboggage
+DescribeDoc=Décrire le Document
+DescribeCSS=Décrire le CSS
+WhatTags=Liste des balises
+ToolAnchor=Inserer balise anchre
+AnchorDialogTitle=Référence de l'Ancre
+TableDialogTitle=Propriétés du Tableau
+DialogAccept=Accepter
+DialogCancel=Annulation
+DialogClose=Fermez
+TableRows=Rangées du Tableau
+TableColumns=Colonnes du Tableau
+TableBorder=Bordures du Tableau
+UndoError=Impossible de défaire
+RedoError=Impossible de refaire
+Help=Aide
+About=L'information
+Index=Index
+Contents=Contenu
+Search=Recherche
+SearchFind=Trouvez
+SearchFindAgain=Trouvez Encore
+SearchReplace=Remplacez
+SearchDialogTitle=Recherche
+SearchStartAtTop=Début En Haut
+SearchReplaceAll=Remplacez Tous
+FiletypeHTML=Dossiers de HTML
+FiletypeCSS=Dossiers de CSS
+FiletypeRTF=Dossiers de RTF
+FiletypeSer=Dossiers de Serialize
+FiletypeIMG=Images
+NoCSSStyle=(aucun)
+ErrorNoTextSelected=Aucun texte n'a été choisi.
diff --git a/ekit/com/hexidec/ekit/LanguageResources_hu_HU.properties b/ekit/com/hexidec/ekit/LanguageResources_hu_HU.properties
new file mode 100644 (file)
index 0000000..1c204e6
--- /dev/null
@@ -0,0 +1,151 @@
+File=File
+New=Új
+NewDocument=Új dokumentum
+OpenDocument=Dokumentum megnyitása
+OpenBase64Document=Dokumentum Base64
+OpenStyle=Stíluslap megnyitása
+SaveDocument=Dokumentum mentése
+Save=Mentés
+SaveAs=Mentés másként
+SaveBody=Body mentése
+SaveRTF=RTF formátumban mentés
+SaveB64=Mentés Base64
+Serialize=Szerializálás
+ReadFromSer=Szerializált olvasás
+Exit=Kilépés
+Edit=Szerkesztés
+Cut=Kivágás
+Copy=Másolás
+Paste=Beillesztés
+Undo=Visszacsinálás
+Redo=Újracsinálás
+SelectAll=Mindet kijelöl
+SelectParagraph=Bekezdés választás
+SelectLine=Sor választás
+SelectWord=Szó választás
+View=Nézet
+ViewToolbar=Eszköztár
+ViewSource=Forrás
+EditMode=Szerkesztés mód
+Font=Betû
+FontBold=Félkövér
+FontItalic=Dõlt
+FontUnderline=Aláhúzott
+FontStrike=Áthúzott
+FontMonospaced=Monospaced
+FontSansserif=Sans-Serif
+FontSerif=Serif
+FontSuperscript=Felsõ index
+FontSubscript=Alsó index
+FontSelect=Betûválasztás
+FontDialogTitle=Válasszon betût
+FontSample=Betûminta
+Color=Szín
+ColorAqua=Víz
+ColorBlack=Fekete
+ColorBlue=Kék
+ColorFuschia=Fuxia
+ColorGray=Szürke
+ColorGreen=Zöld
+ColorLime=Citrom
+ColorMaroon=Maruni
+ColorNavy=Tengeri
+ColorOlive=Oliva
+ColorPurple=Lila
+ColorRed=Vörös
+ColorSilver=Ezüst
+ColorTeal=Kékeszöld
+ColorWhite=Fehér
+ColorYellow=Sárga
+Format=Formázás
+FormatBig=Nagy
+FormatSmall=Kicsi
+FormatSpan=Span
+FormatBlockquote=Blockquote
+FormatPre=Elõformázott
+FormatStrong=Erõs
+FormatEmphasis=Emphasis
+FormatTT=Gépírott
+FormatClear=Formázás törlése
+Heading=Fejléc
+Heading1=Fejléc 1
+Heading2=Fejléc 2
+Heading3=Fejléc 3
+Heading4=Fejléc 4
+Heading5=Fejléc 5
+Heading6=Fejléc 6
+ListUnordered=Rendezetlen lista
+ListOrdered=Rendezett lista
+ListItem=Lista
+Align=Elhelyezkedés
+AlignLeft=Balra helyezkedõ
+AlignCenter=Középre helyezkedõ
+AlignRight=Jobbra helyezkedõ
+AlignJustified=Sorkizárt
+Insert=Beszúrás
+InsertAnchor=Anchor
+InsertBreak=Törés
+InsertHorizontalRule=Vízszintes elválasztó beszúrása
+InsertImage=Kép
+InsertNBSP=Szünet
+Table=Táblázat
+InsertTable=Táblázat
+InsertTableRow=Tábla sor
+InsertTableColumn=Tábla oszlop
+InsertTableCell=Tábla cella
+Debug=Debug
+DescribeDoc=Describe Doc
+DescribeCSS=Describe CSS
+WhatTags=Milyen tageket?
+ToolAnchor=Anchor beszúrása
+AnchorDialogTitle=Anchor hivatkozás
+ImageDialogTitle=Válassza ki a beszúrandó képet
+TableDialogTitle=Táblázat tulajdonságok
+DialogAccept=OK
+DialogCancel=Vissza
+DialogClose=Bezár
+TableRows=Tábla sorok
+TableColumns=Tábla oszlopok
+TableBorder=Keret szélessége
+UndoError=Nem lehet visszacsinálni
+RedoError=Nem lehet újracsinálni
+Help=Segítség
+About=Névjegy
+AboutMessage=Ekit (c)2000-2002 Howard Kistler\nhexidec codex\nwww.hexidec.com
+Index=Index
+Contents=Tartalom
+Search=Keresés
+SearchFind=Keresés
+SearchFindAgain=Újra keres
+SearchReplace=Csere
+SearchDialogTitle=Keresés
+SearchCaseSensitive=Kis/nagybetû érzékenység
+SearchStartAtTop=Tetejénél kezdje
+SearchReplaceAll=Mindet cserél
+Forms=Form-ok
+FormInsertForm=Form beszúrás
+FormTextfield=Szövegmezõ
+FormTextarea=Szövegterület (textarea)
+FormCheckbox=Jelölõdoboz
+FormRadio=Rádiógomb
+FormPassword=Jelszó
+FormButton=Gomb
+FormButtonSubmit=Elküld gomb
+FormButtonReset=Reset gomb
+FormDialogTitle=Form elem tulajdonságai
+Tools=Eszközök
+ToolSpellcheck=Helyesírásellenõrzõ
+ToolSpellcheckDialog=Helyesírásellenõrzés
+FiletypeHTML=HTML Filek
+FiletypeCSS=CSS Filek
+FiletypeRTF=RTF Filek
+FiletypeSer=Szerializált filek
+FiletypeIMG=Képek
+NoCSSStyle=(none)
+Error=Hiba
+ErrorNoTextSelected=Nincs szöveg kijelölve
+ErrorNoOccurencesFound=Nincs ilyen elõfordulás
+ErrorNoMatchFound=Nincs egyezés
+ErrorCannotConvertToList=Nem tudom a kijelölt szöveget listává formázni
+ErrorRuntimeException=Runtime Exception occurred.
+DictionaryFile=english
\ No newline at end of file
diff --git a/ekit/com/hexidec/ekit/LanguageResources_it_CH.properties b/ekit/com/hexidec/ekit/LanguageResources_it_CH.properties
new file mode 100644 (file)
index 0000000..d120c25
--- /dev/null
@@ -0,0 +1,114 @@
+File=File
+New=Nuovo
+NewDocument=Nuovo Documento
+OpenDocument=Apri Documento
+OpenStyle=Apri Stile
+SaveDocument=Salva Documento
+Save=Salva
+SaveAs=Salva come
+SaveBody=Salva Body
+SaveRTF=Salva RTF
+Serialize=Salva Serializzabile
+ReadFromSer=leggi Serializzabile
+Exit=Esci
+Edit=Modifica
+Cut=Taglia
+Copy=Copia
+Paste=Incolla
+Undo=Annulla
+Redo=Ripristina
+SelectAll=Seleziona Tutto
+SelectParagraph=Seleziona Paragrafo
+SelectLine=Seleziona Riga
+SelectWord=Seleziona Parola
+View=Guarda*
+ViewSource=Fonte*
+EditMode=Modificabile
+Font=Carattere
+FontBold=Grassetto
+FontItalic=Corsivo
+FontUnderline=Sottolineato
+FontMonospaced=Courier
+FontSansserif=Sans Serif
+FontSerif=Serif
+Color=Colore
+ColorAqua=Ciano
+ColorBlack=Nero
+ColorBlue=Blu
+ColorFuschia=Fuschia
+ColorGray=Grigio
+ColorGreen=Verde
+ColorLime=Lime
+ColorMaroon=Maroon
+ColorNavy=Marino
+ColorOlive=Oliva
+ColorPurple=Viola
+ColorRed=Rosso
+ColorSilver=Argento
+ColorTeal=Teal
+ColorWhite=Bianco
+ColorYellow=Giallo
+Format=Formato
+FormatBig=Grande
+FormatSmall=Piccolo
+FontSuperscript=Apice
+FontSubscript=Pendice
+Heading=Grandezza
+Heading1=Grandezza 1
+Heading2=Grandezza 2
+Heading3=Grandezza 3
+Heading4=Grandezza 4
+Heading5=Grandezza 5
+Heading6=Grandezza 6
+ListUnordered=Lista Disordinata
+ListOrdered=Lista Ordinata
+ListItem=Lista Elementi
+ListUnorderedItem=Inserisci Elementi Disordinata
+ListOrderedItem=Inserisci Elementi Ordinata
+FormatSpan=Applica Stile
+FormatClear=Annulla Formato
+Align=Alinea
+AlignLeft=Alinea Sinistra
+AlignCenter=Alinea Centrato
+AlignRight=Alinea Destra
+AlignJustified=Alinea Giustificato
+Insert=Inserisci
+InsertAnchor=Ancora
+InsertBreak=A Capo
+InsertHorizontalRule=Barra orizzontale
+InsertLocalImage=Immagine
+InsertTable=Tabella
+InsertTableRow=Inserisci Riga
+InsertTableCell=Inserisci Cella
+Debug=Debug
+DescribeDoc=Descrizione Doc
+DescribeCSS=Descrizione CSS
+WhatTags=Che Tag è?
+ToolAnchor=Inserisci Ancora
+AnchorDialogTitle=Ancora di Referenza
+TableDialogTitle=Proprietà Tabella
+DialogAccept=Accetta
+DialogCancel=Cancella
+DialogClose=Chiuda
+TableRows=Righe Tabella
+TableColumns=Colonne Tabella
+TableBorder=Spessore Bordo
+UndoError=Impossibile Annullare
+RedoError=Impossibile Ripristinare
+Help=Aiuto
+About=Informazioni
+Index=Indice
+Contents=Contenti
+Search=Ricerca
+SearchFind=Trovi
+SearchFindAgain=Trovi Ancora
+SearchReplace=Sostituisca
+SearchDialogTitle=Ricerca
+SearchStartAtTop=Inizio In Cima
+SearchReplaceAll=Sostituisca Tutti
+FiletypeHTML=Documenti del HTML
+FiletypeCSS=Documenti del CSS
+FiletypeRTF=Documenti del RTF
+FiletypeSer=Documenti del Serialized
+FiletypeIMG=Immagini
+NoCSSStyle=(nessun)
diff --git a/ekit/com/hexidec/ekit/LanguageResources_it_IT.properties b/ekit/com/hexidec/ekit/LanguageResources_it_IT.properties
new file mode 100644 (file)
index 0000000..d120c25
--- /dev/null
@@ -0,0 +1,114 @@
+File=File
+New=Nuovo
+NewDocument=Nuovo Documento
+OpenDocument=Apri Documento
+OpenStyle=Apri Stile
+SaveDocument=Salva Documento
+Save=Salva
+SaveAs=Salva come
+SaveBody=Salva Body
+SaveRTF=Salva RTF
+Serialize=Salva Serializzabile
+ReadFromSer=leggi Serializzabile
+Exit=Esci
+Edit=Modifica
+Cut=Taglia
+Copy=Copia
+Paste=Incolla
+Undo=Annulla
+Redo=Ripristina
+SelectAll=Seleziona Tutto
+SelectParagraph=Seleziona Paragrafo
+SelectLine=Seleziona Riga
+SelectWord=Seleziona Parola
+View=Guarda*
+ViewSource=Fonte*
+EditMode=Modificabile
+Font=Carattere
+FontBold=Grassetto
+FontItalic=Corsivo
+FontUnderline=Sottolineato
+FontMonospaced=Courier
+FontSansserif=Sans Serif
+FontSerif=Serif
+Color=Colore
+ColorAqua=Ciano
+ColorBlack=Nero
+ColorBlue=Blu
+ColorFuschia=Fuschia
+ColorGray=Grigio
+ColorGreen=Verde
+ColorLime=Lime
+ColorMaroon=Maroon
+ColorNavy=Marino
+ColorOlive=Oliva
+ColorPurple=Viola
+ColorRed=Rosso
+ColorSilver=Argento
+ColorTeal=Teal
+ColorWhite=Bianco
+ColorYellow=Giallo
+Format=Formato
+FormatBig=Grande
+FormatSmall=Piccolo
+FontSuperscript=Apice
+FontSubscript=Pendice
+Heading=Grandezza
+Heading1=Grandezza 1
+Heading2=Grandezza 2
+Heading3=Grandezza 3
+Heading4=Grandezza 4
+Heading5=Grandezza 5
+Heading6=Grandezza 6
+ListUnordered=Lista Disordinata
+ListOrdered=Lista Ordinata
+ListItem=Lista Elementi
+ListUnorderedItem=Inserisci Elementi Disordinata
+ListOrderedItem=Inserisci Elementi Ordinata
+FormatSpan=Applica Stile
+FormatClear=Annulla Formato
+Align=Alinea
+AlignLeft=Alinea Sinistra
+AlignCenter=Alinea Centrato
+AlignRight=Alinea Destra
+AlignJustified=Alinea Giustificato
+Insert=Inserisci
+InsertAnchor=Ancora
+InsertBreak=A Capo
+InsertHorizontalRule=Barra orizzontale
+InsertLocalImage=Immagine
+InsertTable=Tabella
+InsertTableRow=Inserisci Riga
+InsertTableCell=Inserisci Cella
+Debug=Debug
+DescribeDoc=Descrizione Doc
+DescribeCSS=Descrizione CSS
+WhatTags=Che Tag è?
+ToolAnchor=Inserisci Ancora
+AnchorDialogTitle=Ancora di Referenza
+TableDialogTitle=Proprietà Tabella
+DialogAccept=Accetta
+DialogCancel=Cancella
+DialogClose=Chiuda
+TableRows=Righe Tabella
+TableColumns=Colonne Tabella
+TableBorder=Spessore Bordo
+UndoError=Impossibile Annullare
+RedoError=Impossibile Ripristinare
+Help=Aiuto
+About=Informazioni
+Index=Indice
+Contents=Contenti
+Search=Ricerca
+SearchFind=Trovi
+SearchFindAgain=Trovi Ancora
+SearchReplace=Sostituisca
+SearchDialogTitle=Ricerca
+SearchStartAtTop=Inizio In Cima
+SearchReplaceAll=Sostituisca Tutti
+FiletypeHTML=Documenti del HTML
+FiletypeCSS=Documenti del CSS
+FiletypeRTF=Documenti del RTF
+FiletypeSer=Documenti del Serialized
+FiletypeIMG=Immagini
+NoCSSStyle=(nessun)
diff --git a/ekit/com/hexidec/ekit/LanguageResources_nl_NL.properties b/ekit/com/hexidec/ekit/LanguageResources_nl_NL.properties
new file mode 100644 (file)
index 0000000..b307379
--- /dev/null
@@ -0,0 +1,120 @@
+File=Bestand
+New=Nieuw
+NewDocument=Nieuw document
+OpenDocument=Document openen
+OpenStyle=Stylesheet openen
+SaveDocument=Document opslaan
+Save=Opslaan
+SaveAs=Opslaan als
+SaveBody=Body opslaan
+SaveRTF=Opslaan als RTF
+Serialize=Serialiseren
+ReadFromSer=Lezen van Ser
+Exit=Afsluiten
+Edit=Bewerken
+Cut=Knippen
+Copy=Kopiëren
+Paste=Plakken
+Undo=Ongedaan maken
+Redo=Opnieuw
+SelectAll=Alles selecteren
+SelectParagraph=Selecteer paragraaf
+SelectLine=Selecteer regel
+SelectWord=Selecteer woord
+View=Beeld
+ViewToolbar=Knoppenbalk
+ViewSource=Broncode
+EditMode=Bewerkingsmodus
+Font=Lettertype
+FontBold=Vet
+FontItalic=Cursief
+FontUnderline=Onderstreept
+FontMonospaced=Monospaced
+FontSansserif=Sans-Serif
+FontSerif=Serif
+Color=Kleur
+ColorAqua=Aqua
+ColorBlack=Zwart
+ColorBlue=Blauw
+ColorFuschia=Roze
+ColorGray=Grijs
+ColorGreen=Groen
+ColorLime=Lichtgroen
+ColorMaroon=Donkerrood
+ColorNavy=Marineblauw
+ColorOlive=Olijfgroen
+ColorPurple=Paars
+ColorRed=Rood
+ColorSilver=Zilver
+ColorTeal=Blauwgroen
+ColorWhite=Wit
+ColorYellow=Geel
+Format=Opmaak
+FormatBig=Groot
+FormatSmall=Klein
+FontSuperscript=Superscript
+FontSubscript=Subscript
+FormatBlockquote=Blokcitaat
+FormatPre=Zonder opmaak
+Heading=Kop
+Heading1=Kop 1
+Heading2=Kop 2
+Heading3=Kop 3
+Heading4=Kop 4
+Heading5=Kop 5
+Heading6=Kop 6
+ListUnordered=Lijst zonder cijfers
+ListOrdered=Lijst met cijfers
+ListItem=Lijstitem
+FormatSpan=Span
+FormatClear=Opmaak verwijderen
+Align=Uitlijnen
+AlignLeft=Links uitlijnen
+AlignCenter=Centreren
+AlignRight=Rechts uitlijnen
+AlignJustified=Passend uitlijnen
+Insert=Invoegen
+InsertAnchor=Anker
+InsertBreak=Nieuwe regel
+InsertHorizontalRule=Horizontale lijn
+InsertLocalImage=Afbeelding
+InsertTable=Tabel
+InsertTableRow=Tabelrij
+InsertTableCell=Tabelcel
+Debug=Debug
+DescribeDoc=Beschrijf Doc
+DescribeCSS=Beschrijf CSS
+WhatTags=Welke Tags?
+ToolAnchor=Anker invoegen
+AnchorDialogTitle=Verwijzing naar anker
+TableDialogTitle=Tabeleigenschappen
+DialogAccept=OK
+DialogCancel=Annuleren
+DialogClose=Sluiten
+TableRows=Tabelrijen
+TableColumns=Tabelkolommen
+TableBorder=Randdikte
+UndoError=Kan niet ongedaan maken
+RedoError=Kan niet opnieuw uitvoeren
+Help=Help
+About=Over
+Index=Index
+Contents=Inhoud
+Search=Zoeken
+SearchFind=Zoek
+SearchFindAgain=Zoek meer
+SearchReplace=Vervangen
+SearchDialogTitle=Zoeken
+SearchCaseSensitive=Hoofdlettergevoelig
+SearchStartAtTop=Bovenaan beginnen
+SearchReplaceAll=Alles vervangen
+FiletypeHTML=HTML Bestanden
+FiletypeCSS=CSS Bestanden
+FiletypeRTF=RTF Bestanden
+FiletypeSer=Geserialiseerde bestanden
+FiletypeIMG=Afbeeldingen
+NoCSSStyle=(geen)
+ErrorNoTextSelected=Er is geen tekst geselecteerd.
+ErrorNoOccurencesFound=Geen overeenkomsten gevonden
+ErrorNoMatchFound=Geen overeenkomsten gevonden
+ErrorCannotConvertToList=Kan de geselecteerde tekst niet naar een lijst converteren.
diff --git a/ekit/com/hexidec/ekit/LanguageResources_no_NO.properties b/ekit/com/hexidec/ekit/LanguageResources_no_NO.properties
new file mode 100644 (file)
index 0000000..033394e
--- /dev/null
@@ -0,0 +1,113 @@
+File=Fil
+New=Ny
+NewDocument=Nytt Dokument
+OpenDocument=Åpne Dokument
+OpenStyle=Åpne Stylesheet
+SaveDocument=Lagre Dokument
+Save=Lagre
+SaveAs=Lagre som
+SaveBody=Lagre Body
+SaveRTF=Lagre RTF
+Serialize=Serialisere
+ReadFromSer=Lese fra serialisert
+Exit=Avslutt
+Edit=Endre
+Cut=Klipp
+Copy=Kopier
+Paste=Lime
+Undo=Angre
+Redo=Gjør om
+SelectAll=Marker alt
+SelectParagraph=Velg avsnitt
+SelectLine=Velg linje
+SelectWord=Velg ord
+View=Se
+ViewToolbar=Verktøylinje
+ViewSource=Kilde
+EditMode=Endringsmodus
+Font=Skrift
+FontBold=Fet
+FontItalic=Kurs
+FontUnderline=Understreket
+FontMonospaced=Monospaced
+FontSansserif=Sans-Serif
+FontSerif=Serif
+Color=Farge
+ColorAqua=Aqua
+ColorBlack=Svart
+ColorBlue=Blå
+ColorFuschia=Fuksia
+ColorGray=Grå
+ColorGreen=Grønn
+ColorLime=Lime
+ColorMaroon=Maroon
+ColorNavy=Marine
+ColorOlive=Oliven
+ColorPurple=Purpur
+ColorRed=Rød
+ColorSilver=Sølvgrå
+ColorTeal=Teal
+ColorWhite=Hvit
+ColorYellow=Gul
+Format=Formatere
+FormatBig=Stor
+FormatSmall=Liten
+FontSuperscript=Superskrift
+FontSubscript=Subskrift
+Heading=Overskrift
+Heading1=Overskrift 1
+Heading2=Overskrift 2
+Heading3=Overskrift 3
+Heading4=Overskrift 4
+Heading5=Overskrift 5
+Heading6=Overskrift 6
+ListUnordered=Punktliste
+ListOrdered=Nummerert liste
+ListItem=Listepunkt
+FormatSpan=Span
+FormatClear=Fjern formattering
+Align=Juster
+AlignLeft=Venstrejuster
+AlignCenter=Midstill
+AlignRight=Høyrejuster
+AlignJustified=Rett høyremarg
+Insert=Sett inn
+InsertAnchor=Lenke
+InsertBreak=Linjeskift
+InsertHorizontalRule=Horisontal strek
+InsertLocalImage=Bilde
+InsertTable=Tabell
+InsertTableRow=Tabellrad
+InsertTableCell=Tabellcelle
+Debug=Spor feil
+DescribeDoc=Beskrive Doc
+DescribeCSS=Beskrive CSS
+WhatTags=Hvilke tagger?
+ToolAnchor=Sett inn lenke
+AnchorDialogTitle=Oppgi adresse/URL
+TableDialogTitle=Tabellegenskaper
+DialogAccept=OK
+DialogCancel=Avbryt
+DialogClose=Lukk
+TableRows=Tabellrader
+TableColumns=Tabellkolonner
+TableBorder=Marg
+UndoError=Kan ikke angre
+RedoError=Kan ikke gjøre om
+Help=Hjelp
+About=Om
+Index=Index
+Contents=Innhold
+Search=Søk
+SearchFind=Finn
+SearchFindAgain=Finn igjen
+SearchReplace=Erstatt
+SearchDialogTitle=Søk
+SearchCaseSensitive=Skill store/små bokstaver
+SearchStartAtTop=Start på toppen
+SearchReplaceAll=Erstatt Alle
+FiletypeHTML=HTML-filer
+FiletypeCSS=CSS-filer
+FiletypeRTF=RTF-filer
+FiletypeSer=Serialiserte filer
+FiletypeIMG=Bilde-filer
\ No newline at end of file
diff --git a/ekit/com/hexidec/ekit/LanguageResources_pt_BR.properties b/ekit/com/hexidec/ekit/LanguageResources_pt_BR.properties
new file mode 100644 (file)
index 0000000..43ebba4
--- /dev/null
@@ -0,0 +1,99 @@
+File=Arquivo
+New=Novo
+NewDocument=Novo Documento
+OpenDocument=Abrir Documento
+OpenStyle=Abrir Estilo
+SaveDocument=Salvar Documento
+Save=Salvar
+SaveAs=Salvar com
+SaveBody=Salvar Corpo
+SaveRTF=Salvar RTF
+Serialize=Serializar
+ReadFromSer=Carregar Serializado
+Exit=Sair
+Edit=Editar
+Cut=Recortar
+Copy=Copiar
+Paste=Colar
+Undo=Voltar
+Redo=Avançar
+SelectAll=Selecionar Todos
+SelectParagraph=Selecionar Paragráfo
+SelectLine=Selecionar Linha
+SelectWord=Selecionar Palavra
+View=Visualizar
+ViewToolbar=Ferramentas
+ViewSource=Código-fonte
+EditMode=Editar Modo
+Font=Fonte
+FontBold=Negrito
+FontItalic=Itálico
+FontUnderline=Sublinhado
+FontMonospaced=Monoespaçado
+FontSansserif=Sans-Serif
+FontSerif=Serif
+Color=Cor
+ColorAqua=Ciano
+ColorBlack=Preto
+ColorBlue=Azul
+ColorFuschia=Fuschia
+ColorGray=Cinza
+ColorGreen=Verde
+ColorLime=Cal
+ColorMaroon=Maroon
+ColorNavy=Marinha
+ColorOlive=Azeitona
+ColorPurple=Roxo
+ColorRed=Vermelho
+ColorSilver=Prata
+ColorTeal=Teal
+ColorWhite=Branco
+ColorYellow=Amarelo
+Format=Formatar
+FormatBig=Grande
+FormatSmall=Pequeno
+FontSuperscript=Sobrescrito
+FontSubscript=Subescrito
+Heading=Título
+Heading1=Título 1
+Heading2=Título 2
+Heading3=Título 3
+Heading4=Título 4
+Heading5=Título 5
+Heading6=Título 6
+ListUnordered=Lista não Ordenada
+ListOrdered=List Ordenada
+ListItem=Item de Lista
+ListUnorderedItem=Inserir Item de Lista não Ordenada
+ListOrderedItem=Inserir Item de Lista Ordenada
+FormatSpan=Extensão
+FormatClear=Limpar Formatação
+Align=Alinhar
+AlignLeft=Alinhar à Esquerda
+AlignCenter=Alinha ao Centro
+AlignRight=Alinhar à Direita
+AlignJustified=Justificado
+Insert=Inserir
+InsertAnchor=Ancora
+InsertBreak=Break
+InsertHorizontalRule=Linha Horizontal
+InsertLocalImage=Imagem
+InsertTable=Tabela
+InsertTableRow=Inserir Linha
+InsertTableCell=Inserir Coluna
+Debug=Debug
+DescribeDoc=Descrever Doc
+DescribeCSS=Descrever CSS
+WhatTags=O que são Tags?
+ToolAnchor=Inserir Ancora
+AnchorDialogTitle=Ancora de Referência
+TableDialogTitle=Propriedades da Tabela
+DialogAccept=Aceitar
+DialogCancel=Cancelar
+DialogClose=Feche
+TableRows=Quantidade de Linhas
+TableColumns=Quantidade de Tabelas
+TableBorder=Largura da Borda
+UndoError=Incapaz de Voltar
+RedoError=Incapaz de Avançar
+Help=Ajuda
diff --git a/ekit/com/hexidec/ekit/LanguageResources_pt_PT.properties b/ekit/com/hexidec/ekit/LanguageResources_pt_PT.properties
new file mode 100644 (file)
index 0000000..43ebba4
--- /dev/null
@@ -0,0 +1,99 @@
+File=Arquivo
+New=Novo
+NewDocument=Novo Documento
+OpenDocument=Abrir Documento
+OpenStyle=Abrir Estilo
+SaveDocument=Salvar Documento
+Save=Salvar
+SaveAs=Salvar com
+SaveBody=Salvar Corpo
+SaveRTF=Salvar RTF
+Serialize=Serializar
+ReadFromSer=Carregar Serializado
+Exit=Sair
+Edit=Editar
+Cut=Recortar
+Copy=Copiar
+Paste=Colar
+Undo=Voltar
+Redo=Avançar
+SelectAll=Selecionar Todos
+SelectParagraph=Selecionar Paragráfo
+SelectLine=Selecionar Linha
+SelectWord=Selecionar Palavra
+View=Visualizar
+ViewToolbar=Ferramentas
+ViewSource=Código-fonte
+EditMode=Editar Modo
+Font=Fonte
+FontBold=Negrito
+FontItalic=Itálico
+FontUnderline=Sublinhado
+FontMonospaced=Monoespaçado
+FontSansserif=Sans-Serif
+FontSerif=Serif
+Color=Cor
+ColorAqua=Ciano
+ColorBlack=Preto
+ColorBlue=Azul
+ColorFuschia=Fuschia
+ColorGray=Cinza
+ColorGreen=Verde
+ColorLime=Cal
+ColorMaroon=Maroon
+ColorNavy=Marinha
+ColorOlive=Azeitona
+ColorPurple=Roxo
+ColorRed=Vermelho
+ColorSilver=Prata
+ColorTeal=Teal
+ColorWhite=Branco
+ColorYellow=Amarelo
+Format=Formatar
+FormatBig=Grande
+FormatSmall=Pequeno
+FontSuperscript=Sobrescrito
+FontSubscript=Subescrito
+Heading=Título
+Heading1=Título 1
+Heading2=Título 2
+Heading3=Título 3
+Heading4=Título 4
+Heading5=Título 5
+Heading6=Título 6
+ListUnordered=Lista não Ordenada
+ListOrdered=List Ordenada
+ListItem=Item de Lista
+ListUnorderedItem=Inserir Item de Lista não Ordenada
+ListOrderedItem=Inserir Item de Lista Ordenada
+FormatSpan=Extensão
+FormatClear=Limpar Formatação
+Align=Alinhar
+AlignLeft=Alinhar à Esquerda
+AlignCenter=Alinha ao Centro
+AlignRight=Alinhar à Direita
+AlignJustified=Justificado
+Insert=Inserir
+InsertAnchor=Ancora
+InsertBreak=Break
+InsertHorizontalRule=Linha Horizontal
+InsertLocalImage=Imagem
+InsertTable=Tabela
+InsertTableRow=Inserir Linha
+InsertTableCell=Inserir Coluna
+Debug=Debug
+DescribeDoc=Descrever Doc
+DescribeCSS=Descrever CSS
+WhatTags=O que são Tags?
+ToolAnchor=Inserir Ancora
+AnchorDialogTitle=Ancora de Referência
+TableDialogTitle=Propriedades da Tabela
+DialogAccept=Aceitar
+DialogCancel=Cancelar
+DialogClose=Feche
+TableRows=Quantidade de Linhas
+TableColumns=Quantidade de Tabelas
+TableBorder=Largura da Borda
+UndoError=Incapaz de Voltar
+RedoError=Incapaz de Avançar
+Help=Ajuda
diff --git a/ekit/com/hexidec/ekit/LanguageResources_sl_SI.properties b/ekit/com/hexidec/ekit/LanguageResources_sl_SI.properties
new file mode 100644 (file)
index 0000000..23f0cba
--- /dev/null
@@ -0,0 +1,85 @@
+File=Datoteka
+New=Nov
+NewDocument=Nov Dokument
+OpenDocument=Odpri Dokument
+OpenStyle=Odpri slog
+SaveDocument=Shrani Dokument
+Save=Shrani
+SaveAs=Shrani kot
+SaveBody=Shrani telo
+SaveRTF=Shrani RTF
+Serialize=Predelaj v Nize
+ReadFromSer=Beri Iz Ser
+Exit=Izhod
+Edit=Uredi
+Cut=Izre\9ei
+Copy=Kopiraj
+Paste=Prilepi
+Undo=Razveljavi
+Redo=Ponovi
+SelectAll=Izberi Vse
+SelectParagraph=Izberi Odstavek
+SelectLine=Izberi Vrstico
+SelectWord=Izberi Besedo
+View=Pogled
+ViewToolbar=Orodna Vrstica
+ViewSource=Izvor
+EditMode=Urejevalni naèin
+Font=Pisava
+FontBold=Krepko
+FontItalic=Po\9aevno
+FontUnderline=Podèrtano
+FontMonospaced=Z Enojnim Presledkom
+FontSansserif=Sans-Serif
+FontSerif=Serif
+Color=Farba
+ColorBlack=Èrna
+ColorGray=Siva
+ColorRed=Rdeèa
+ColorGreen=Zelena
+ColorBlue=Modra
+Format=Format
+FormatBig=Velik
+FormatSmall=Majhen
+FontSuperscript=Nadpisano
+FontSubscript=Podpisano
+Heading=Naslov
+Heading1=Naslov 1
+Heading2=Naslov 2
+Heading3=Naslov 3
+Heading4=Naslov 4
+Heading5=Naslov 5
+Heading6=Naslov 6
+ListUnordered=Neurejen Seznam
+ListOrdered=Urejen Seznam
+ListItem=Element
+FormatSpan=Izbor
+FormatClear=Izbri\9ai obliko
+Align=Poravnaj
+AlignLeft=Poravnaj Na Levo
+AlignCenter=Poravnaj Na Sredino
+AlignRight=Poravnaj Na Desno
+AlignJustified=Poravnaj Dvosmerno
+Insert=Vstavi
+InsertAnchor=Sidro
+InsertBreak=Prelom
+InsertHorizontalRule=Vodoravno Pravilo
+InsertLocalImage=Slika
+InsertTable=Tabela
+InsertTableRow=Vrstica Tabele
+InsertTableCell=Celica Tabele
+Debug=Razhro\9aèi
+DescribeDoc=Opi\9ai Doc
+DescribeCSS=Opi\9ai CSS
+WhatTags=Katere Oznaèbe?
+ToolAnchor=Vnesi Sidro
+AnchorDialogTitle=Naslov Sidra
+TableDialogTitle=Lastnosti Tabele
+DialogAccept=Izberi
+DialogCancel=Prekini
+TableRows=Vrstice Tabele
+TableColumns=Stolpci Tabele
+TableBorder=Rob Tabele
+UndoError=Razveljavitev ni mogoèa
+RedoError=Ponovitev ni mogoèa
+Help=Pomoè
\ No newline at end of file
diff --git a/ekit/com/hexidec/ekit/LanguageResources_zh_CN.properties b/ekit/com/hexidec/ekit/LanguageResources_zh_CN.properties
new file mode 100644 (file)
index 0000000..b0ea96e
--- /dev/null
@@ -0,0 +1,149 @@
+File=\u6587\u4EF6
+New=\u65B0\u5EFA
+NewDocument=\u65B0\u5EFA\u6587\u6863
+OpenDocument=\u6253\u5F00\u6587\u6863
+OpenStyle=\u6253\u5F00\u6837\u5F0F\u8868\
+SaveDocument=\u4FDD\u5B58\u6587\u6863
+Save=\u4FDD\u5B58
+SaveAs=\u4FDD\u5B58\u4E3A
+SaveBody=\u4FDD\u5B58 Body
+SaveRTF=\u4FDD\u5B58 RTF
+Serialize=\u5E8F\u5217\u5316
+ReadFromSer=\u4ECESer\u8BFB\u53D6
+Exit=\u9000\u51FA
+Edit=\u7F16\u8F91
+Cut=\u526A\u5207
+Copy=\u590D\u5236
+Paste=\u7C98\u8D34
+Undo=\u64A4\u6D88
+Redo=\u6062\u590D
+SelectAll=\u9009\u62E9\u6240\u6709
+SelectParagraph=\u9009\u62E9\u6BB5\u843D
+SelectLine=\u9009\u62E9\u884C
+SelectWord=\u9009\u62E9\u5B57
+View=\u89C6\u56FE
+ViewToolbar=\u5DE5\u5177\u680F
+ViewSource=\u6E90
+EditMode=\u7F16\u8F91\u6A21\u5F0F
+Font=\u5B57\u4F53
+FontBold=\u7C97\u4F53
+FontItalic=\u659C\u4F53\u5B57
+FontUnderline=\u4E0B\u5212\u7EBF
+FontStrike=\u8D2F\u7A7F\u7EBF
+FontMonospaced=\u7B49\u5BBD
+FontSansserif=Sans-Serif
+FontSerif=Serif
+FontSelect=\u9009\u62E9\u5B57\u4F53
+FontDialogTitle=\u9009\u62E9\u5B57\u4F53
+FontSample=\u5B57\u4F53\u4F8B\u5B50
+Color=\u989C\u8272
+ColorAqua=\u6D45\u7EFF\u8272
+ColorBlack=\u9ED1\u8272
+ColorBlue=\u84DD\u8272
+ColorFuschia=\u7D2B\u7EA2\u8272
+ColorGray=\u7070\u8272
+ColorGreen=\u7EFF\u8272
+ColorLime=\u6D45\u7EFF\u8272
+ColorMaroon=\u6817\u8272
+ColorNavy=\u6DF1\u84DD\u8272
+ColorOlive=\u6A44\u6984\u8272
+ColorPurple=\u7D2B\u8272
+ColorRed=\u7EA2\u8272
+ColorSilver=\u94F6\u7070\u8272
+ColorTeal=\u6DF1\u9752\u8272
+ColorWhite=\u767D\u8272
+ColorYellow=\u9EC4\u8272
+Format=\u683C\u5F0F
+FormatBig=\u5927
+FormatSmall=\u5C0F
+FontSuperscript=\u4E0A\u6807
+FontSubscript=\u4E0B\u6807
+Heading=\u6807\u9898
+Heading1=\u6807\u9898 1
+Heading2=\u6807\u9898 2
+Heading3=\u6807\u9898 3
+Heading4=\u6807\u9898 4
+Heading5=\u6807\u9898 5
+Heading6=\u6807\u9898 6
+ListUnordered=\u672A\u6392\u5E8F\u5217\u8868
+ListOrdered=\u6392\u5E8F\u5217\u8868
+ListItem=\u5217\u8868\u9879
+FormatBlockquote=\u5757\u5F15\u7528
+FormatPre=\u9884\u8BBE\u683C\u5F0F
+FormatSpan=\u8DE8\u5EA6
+FormatStrong=\u589E\u5F3A
+FormatEmphasis=\u52A0\u91CD
+FormatTT=Typewritten
+FormatClear=\u6E05\u9664\u683C\u5F0F
+Align=\u5BF9\u9F50
+AlignLeft=\u5DE6\u5BF9\u9F50
+AlignCenter=\u4E2D\u95F4\u5BF9\u9F50
+AlignRight=\u53F3\u5BF9\u9F50
+AlignJustified=\u5BF9\u9F50\u6821\u6B63
+Insert=\u63D2\u5165
+InsertAnchor=\u56FA\u5B9A
+InsertBreak=\u4E2D\u65AD
+InsertHorizontalRule=\u6C34\u5E73\u7EBF
+InsertImage=\u56FE
+InsertNBSP=Nonbreaking Space
+InsertTable=\u8868
+InsertTableRow=\u8868\u884C
+InsertTableCell=\u8868\u5355\u5143
+Debug=\u8C03\u8BD5
+DescribeDoc=Describe Doc
+DescribeCSS=Describe CSS
+WhatTags=What Tags?
+ToolAnchor=\u63D2\u5165 Anchor
+AnchorDialogTitle=\u56FA\u5B9A
+ImageDialogTitle=\u9009\u62E9\u56FE\u7247\u63D2\u5165
+TableDialogTitle=\u8868\u5C5E\u6027
+DialogAccept=\u63A5\u53D7
+DialogCancel=\u53D6\u6D88
+DialogClose=\u5173\u95ED
+TableRows=\u8868\u884C
+TableColumns=\u8868\u5217
+TableBorder=\u8FB9\u6846\u5BBD\u5EA6
+TableCellSpacing=\u5355\u5143\u7A7A\u95F4
+TableCellPadding=\u5355\u5143\u586B\u5145
+UndoError=\u4E0D\u80FD\u64A4\u6D88
+RedoError=\u4E0D\u80FD\u6062\u590D
+Help=\u5E2E\u52A9
+About=\u5173\u4E8E
+AboutMessage=Ekit (c)2000-2002 Howard Kistler\nhexidec codex\nwww.hexidec.com
+Index=\u7D22\u5F15
+Contents=\u5185\u5BB9
+Search=\u67E5\u627E
+SearchFind=\u627E
+SearchFindAgain=\u518D\u6B21\u627E
+SearchReplace=\u66FF\u6362
+SearchDialogTitle=\u67E5\u627E
+SearchCaseSensitive=\u5927\u5C0F\u5199\u654F\u611F
+SearchStartAtTop=\u5728\u9876\u90E8\u5F00\u59CB
+SearchReplaceAll=\u5168\u90E8\u66FF\u6362
+Forms=\u8868\u5355
+FormInsertForm=\u63D2\u5165\u8868\u5355
+FormTextfield=\u6587\u672C\u57DF
+FormTextarea=\u6587\u672C\u533A
+FormCheckbox=\u590D\u9009\u6846
+FormRadio=\u5355\u9009\u6309\u94AE
+FormPassword=\u5BC6\u7801
+FormButton=\u6309\u94AE
+FormButtonSubmit=\u63D0\u4EA4\u6309\u94AE
+FormButtonReset=\u91CD\u8BBE\u6309\u94AE
+FormDialogTitle=\u8868\u5355\u5143\u7D20\u5C5E\u6027
+Tools=\u5DE5\u5177
+ToolSpellcheck=\u62FC\u5199\u68C0\u6D4B
+ToolSpellcheckDialog=\u68C0\u6D4B\u62FC\u5199\u68C0\u6D4B
+FiletypeHTML=HTML \u6587\u4EF6
+FiletypeCSS=CSS \u6587\u4EF6
+FiletypeRTF=RTF \u6587\u4EF6
+FiletypeSer=\u5E8F\u5217\u5316\u6587\u4EF6
+FiletypeIMG=\u56FE
+NoCSSStyle=(\u65E0)
+Error=\u9519\u8BEF
+ErrorNoTextSelected=\u65E0\u6587\u672C\u88AB\u9009\u4E2D
+ErrorNoOccurencesFound=\u672A\u53D1\u73B0\u5177\u4F53\u503C
+ErrorNoMatchFound=\u672A\u53D1\u73B0\u5339\u914D
+ErrorCannotConvertToList=\u4E0D\u80FD\u8F6C\u6362\u88AB\u9009\u6587\u672C\u5230\u5217\u8868
+ErrorRuntimeException=\u53D1\u751F\u8FD0\u884C\u65F6\u9519\u8BEF
+DictionaryFile=\u82F1\u6587
\ No newline at end of file
diff --git a/ekit/com/hexidec/ekit/README b/ekit/com/hexidec/ekit/README
new file mode 100644 (file)
index 0000000..6f011ce
--- /dev/null
@@ -0,0 +1,694 @@
+==========================
+Ekit README
+==========================
+
+Ekit v0.9g (C)2000-2003 Howard Kistler/hexidec codex
+App/Applet for editing and saving HTML in a Java text component.
+
+
+ABOUT
+--------------------------
+
+Ekit is a program & applet that uses the Java 2 libraries to create an HTML
+editor. The Ekit standalone also allows for HTML to be loaded and saved, as
+well as serialized and saved as an RTF. It is currently an advanced beta,
+and most features work fine.
+
+Updates to this and other hexidec codex projects can be found here:
+
+http://www.hexidec.com/
+
+Please feel free to share any enhancements or bug reports with me at:
+
+hexidec@telepath.com
+
+
+ABOUT LICENSE
+--------------------------
+
+Ekit was originally distributed under the GPL license. However, it was brought
+to my attention that the GPL license is not suited for programs that link to
+non-GPL libraries, such as Ekit does by linking to the Sun Swing library.
+Hence, I have changed the licensing on Ekit to the LGPL, which is more
+appropriate. This should not impact any Ekit users adversely, as anyone who
+was using it before under the GPL can still do so without any conflicts under
+the LGPL. In addition, this opens up Ekit for use with more projects which
+might contain some proprietary libraries of their own as well. It is my
+intention through this change to make Ekit conform better to open source
+licensing and to make Ekit more available and accessible to developers and
+users, and I think by switching to the LGPL all of these criteria are thus met.
+
+I am aware that releasing a product under the GPL is supposed to be an
+"irreversible" process. However, as this product was in violation of the
+stricter terms of the GPL, this reassignment to LGPL is not a change so much
+as a correction of licensing.
+
+
+REQUIREMENTS
+--------------------------
+
+Ekit requires the following software:
+    - Java 2 (Sun JDK 1.3 or later, or compatible variant)
+    - Swing Library (standard with Java 2)
+
+EkitApplet requires the following software:
+    - Browser with Java Plug-in 1.3 or later
+
+Sun JDK Standard Edition Homepage : http://java.sun.com/j2se/
+Sun JDK 1.3 available here : http://java.sun.com/j2se/1.3/
+Sun JDK 1.4 available here : http://java.sun.com/j2se/1.4/
+
+
+FILES
+--------------------------
+
+These are the base class source files:
+
+EkitCore.java   - Source for the core Ekit functionality
+Ekit.java       - Source for Ekit application shell
+EkitApplet.java - Source for EkitApplet shell
+
+EkitCore is replaced by one of these two core files during compilation:
+
+EkitCore_Basic.java - The standard Ekit core.
+EkitCore_Spell.java - The core plus supports for the Jazzy spellchecker.
+
+The "action" subdirectory contains these action class sources:
+
+CustomAction.java         - Special situation actions (like anchor insertion)
+FormatAction.java         - General text format actions (like subscript)
+ListAutomationAction.java - Bulleted/Numbered List creation actions
+StylesAction.java         - CSS Style actions
+
+The "component" subdirectory contains these component class sources:
+
+ExtendedHTMLDocument.java    - HTMLDocument with custom functionality
+ExtendedHTMLEditorKit.java   - HTMLEditorKit with custom functionality
+FileDialog.java              - Dialog for loading files from server
+FontSelectorDialog.java      - Dialog for applying system fonts to text
+HTMLUtilities.java           - Special utility functions
+ImageDialog                  - Dialog for loading images from server
+ImageFileChooser.java        - Image selector dialog
+ImageFileChooserPreview.java - Image preview rendering panel
+JButtonNoFocus.java          - JButton that does not obtain focus
+JComboBoxNoFocus.java        - JComboBox that does not obtain focus
+JToggleButtonNoFocus.java    - JToggleButton that does not obtain focus
+MutableFilter.java           - Filetype dialog filter
+PropertiesDialog.java        - Generic parameter request dialog
+RelativeImageView.java       - HTML Image rendering component
+SearchDialog.java            - Find/Replace dialog
+SimpleInfoDialog.java        - Basic message dialog
+TableInputDialog.java        - Table specification input dialog
+UserInputAnchorDialog.java   - Custom anchor input dialog
+UserInputDialog.java         - Custom data input dialog
+
+  There is also a copy of the TaggingDriverServlet.java source within the
+  "materials" folder. You may use this on your server for server-based file
+  and image loading.
+
+The "icons" subdirectory contains these custom icons for the ToolBar:
+
+AnchorHK.gif      - "Make Anchor" ToolBar Icon
+BoldHK.gif        - "Bold Text" ToolBar Icon
+ClearFormatHK.gif - "Clear Format Action" ToolBar Icon
+CopyHK.gif        - "Copy Action" ToolBar Icon
+CutHK.gif         - "Cut Action" ToolBar Icon
+ItalicHK.gif      - "Italicise Text" ToolBar Icon
+NewHK.gif         - "New Document" ToolBar Icon
+OListHK.gif       - "Ordered List" ToolBar Icon
+OpenHK.gif        - "Open Document" ToolBar Icon
+PasteHK.gif       - "Paste Action" ToolBar Icon
+SaveHK.gif        - "Save Document" ToolBar Icon
+SourceHK.gif      - "View Source" ToolBar Icon
+StrikeHK.gif      - "Strike Text" ToolBar Icon
+SubHK.gif         - "Subscript Text" ToolBar Icon
+SuperHK.gif       - "Superscript Text" ToolBar Icon
+UListHK.gif       - "Unordered List" ToolBar Icon
+UnderlineHK.gif   - "Underline Text" ToolBar Icon
+
+  The "HK" suffix merely designates that they are my designs. You can replace
+  these images with your own icons if you wish.
+
+The "com/hexidec/util" directory contains these standard hexidec codex tools:
+
+Base64Codec.java - Base64 encoding/decoding class
+Translatrix.java - Translation resource handler class
+
+These are the ancillary files that are included with the standard Ekit
+source distribution:
+
+ekit.manifest       - Jar manifest file for ekit.jar
+MakeEkit.csh        - Script to (re)build the ekit.jar file (Unix/MacOSX)
+MakeEkitApplet.csh  - Script to (re)build the ekitapplet.jar file (Unix/MacOSX)
+MakeEkit.bat        - Batch file to (re)build the ekit.jar file (Windows)
+MakeEkitApplet.bat  - Batch file to (re)build the ekitapplet.jar file (Windows)
+MakeEkit.ant        - XML file to (re)build the ekit.jar file using Ant
+MakeEkitApplet.ant  - XML file to (re)build the ekitapplet.jar file using Ant
+ekit.css            - Default CSS Stylesheet for Ekit documents
+EkitAppletDemo.html - Example web page for displaying Ekit applet
+RunEkit.csh         - Script for launching Ekit (Unix/MacOSX)
+RunEkit.bat         - Batch file for launching Ekit (Windows)
+README              - This document
+materials/LGPL      - Copy of the Lesser GNU Public License
+
+The distribution also contains these pre-compiled Ekit JARs:
+
+Basic Version
+
+    ekit.jar
+    ekitapplet.jar
+
+Spellcheck Version
+
+    ekitspell.jar
+    ekitappletspell.jar
+
+NOTE : If you want to use the spellcheck versions, move or delete the basic
+versions and rename the spellcheck versions to the basic names. So, for
+example, ekitspell.jar should be renamed ekit.jar.
+
+
+JAZZY SOURCES
+--------------------------
+
+Ekit optionally incorporates a modified subset of the Jazzy open source
+spellchecker. The root folder of the Jazzy classes is "com/swabunga/spell".
+You will find the following subdirectories and sources there. (See the README
+file under the "swabunga" directory for more information.)
+
+The "engine" subdirectory contains the basic mechanics of the spellchecker.
+
+Configuration.java
+DoubleMeta.java
+EditDistance.java
+GenericTransformator.java
+PropertyConfiguration.java
+SpellDictionary.java
+Transformator.java
+Word.java
+configuration.properties
+
+The "dictionary" subdirectory beneath "engine" houses the available
+dictionary files. Currently there is only an English dictionary included.
+
+english - English dictionary file
+
+The "event" sudirectory contains the various event classes and functional
+methods for the spellchecker.
+
+BasicSpellCheckEvent.java
+DocumentWordTokenizer.java
+SpellCheckEvent.java
+SpellCheckListener.java
+SpellChecker.java
+StringWordTokenizer.java
+WordTokenizer.java
+
+The "swing" subdirectory contains the GUI components and message lists.
+
+JSpellDialog.java
+JSpellForm.java
+messages.properties
+messages_sv.properties
+
+
+COMPILATION (OPTIONAL)
+--------------------------
+
+If you modify the included .java files, or need to recreate the .class files,
+use the following commands within the "source" directory to build them. All
+commands assume you are at the top of the source tree (the directory containing
+the "com" directory). All commands listed are one-line commands as well, though
+some are broken to multiple lines in this file due to length. Also note that
+the backslash ("\") character should be replaced by the appropriate path
+separator for your operating system if it is different.
+
+Unix or Mac OS X users may run the MakeEkit.csh and MakeEkitApplet.csh scripts
+from a terminal window. Remember to preface them with "./" when running from
+within the code directory.
+
+Windows users may double-click the MakeEkit.bat and MakeEkitApplet.bat batch
+files, or execute them from the command line.
+
+Both sets of batch files take an optional command line argument. You can enter
+"basic" after the batch file to compile the standard Ekit classes, or enter
+"spell" after the batch file to build in the Jazzy spellchecker classes.
+
+For example, here is a standard build of EkitApplet on Unix:
+
+    MakeEkitApplet.csh
+
+    or
+
+    MakeEkitApplet.csh basic
+
+Here is an example of building Ekit with spellchecking on Windows:
+
+    MakeEkit.bat spell
+
+Apache Ant (http://jakarta.apache.org/ant/) users may use the included .ant XML
+files to compile and build the Ekit jar files with Ant.
+
+You may manually compile Ekit with the following command:
+
+    Unix/MacOSX  javac com/hexidec/ekit/Ekit.java
+    Windows      javac com\hexidec\ekit\Ekit.java
+    Apache Ant   ant -buildfile MakeEkit.ant
+
+You may manually compile EkitApplet with the following command:
+
+    Unix/MacOSX  javac com/hexidec/ekit/EkitApplet.java
+    Windows      javac com\hexidec\ekit\EkitApplet.java
+    Apache Ant   ant -buildfile MakeEkitApplet.ant
+
+Ekit takes no special arguments during compile. The above command assumes your
+Java development environment is configured according to minimal standards and
+can locate the relevant Java core files properly.
+
+View the .csh or .bat files for the proper syntax to manually create the jar
+files under your OS.
+
+
+EXECUTION (APP)
+--------------------------
+
+All users with properly configured systems will be able to launch Ekit by
+double-clicking on the "ekit.jar" file. Unix/MacOSX users may lanuch Ekit with
+the "RunEkit.csh" script. Windows users may launch Ekit by double-clicking the
+batch file "RunEkit.bat".
+
+You may manually execute Ekit from the command line with the following command
+from within the directory containing the ekit.jar file:
+
+    java -jar ekit.jar com.hexidec.ekit.Ekit
+        [-t/T] [-s/S] [-m/M] [-x/X] [-d/D]
+        [-fHTMLfile] [-cCSSfile] [-rRawHTML] [-lLangcode]
+
+Note that your CLASSPATH settings should include the "current directory"
+specifier "." for this to work.
+
+The [optional] command line arguments are:
+
+    -t/-T : Show/Hide the ToolBar (Show by default)
+    -s/-S : Show/Hide the Source window (Hide by default)
+    -m/-M : Show/Omit Menu icons (Show by default)
+    -x/-X : Exclusive Edit Mode On/Off (On by default)
+    -b/-B : Document is/isn't Base64 encoded (Isn't by default)
+    -d/-D : Show/Hide the Debug menu (Hide by default)
+    -f    : Load the HTML document specified by HTMLfile
+    -c    : Load the CSS stylesheet specified by CSSfile
+    -r    : Load the raw HTML string specified by RawHTML
+    -l    : Start Ekit in the language specified by Langcode*
+
+[* Langcode is a combination of the 2-letter language and country codes, in the
+format "xx_XX", where xx is the language code and XX is the country code. For
+example, the Langcode for English/United States is "en_US", English/United
+Kingdom is "en_UK", and German/Germany is "de_DE". Note that there must be
+a matching "LanguageResources_xx_XX.properties" file in the com/hexidec/ekit
+directory for the language you want to use. Missing language files, and
+existing language files that may be missing words in use, will take words from
+the "LanguageResources.properties" file, which contains default words in
+"en_US" encoding marked with a trailing asterisk.]
+
+So, for example, to start Ekit with the ToolBar hidden, the Source window
+showing, and pre-load it with the "Home.html" document and "Styles.css" 
+stylesheet, you would enter:
+
+    java -jar ekit.jar com.hexidec.ekit.Ekit -T -s -fHome.html -cStyles.css
+
+To start Ekit with a short example HTML document written as a raw string, you
+could enter:
+
+    java -jar ekit.jar com.hexidec.ekit.Ekit -r"<HTML><BODY>This is a <B>test
+        </B></BODY></HTML>"
+
+To start Ekit with the Italian/Italy language file:
+
+    java -jar ekit.jar com.hexidec.ekit.Ekit -lit_IT
+
+Note that you shouldn't have to specify the language setting if you want Ekit
+to run in your native language, provided there is an appropriate language file
+in the com/hexidec/ekit directory and your Java environment is configured to
+use your language by default.
+
+
+EXECUTION (APPLET)
+--------------------------
+
+Embed the Ekit applet in a web page and view in an appropriate browser.
+The jar file should be included in the directory with the web page and
+it should also be "visible" to the web server.
+
+The included "EkitAppletDemo.html" page contains the code necessary to
+view the applet properly. You may use this as the basis for including
+Ekit in your own web pages.
+
+
+COMMAND SUMMARY
+--------------------------
+
+File Menu
+
+    New Document - Create new document (clear current one if exists).
+    Open Document - Load an HTML document into the editor.
+    Open Stylesheet - Load CSS stylesheet and apply it to the current document.
+    Open Base64 Document - Load a Base64 encoded document into the editor.
+    Save - Save the current document (prompts for filename if new document).
+    Save As - Save the document with the name specified in the file chooser.
+    Save Body - Save the document after deleting the HEAD element.
+    Save RTF - Save the document in Rich Text Format (RTF).
+    Save Base64 - Save the document in Base64 encoding.
+    Serialize - Save the document in the default Java serialization form.
+    Read From Ser - Load a serialized document into the editor.
+    Exit - Close the app (you will lose any unsaved work).
+
+Edit Menu
+
+    Cut - Remove the selected text and place it in the clipboard.
+    Copy - Place a copy of the selected text in the clipboard.
+    Paste - Place the contents of clipboard into the document at the current
+        cursor position.
+    Undo - Undo the previous action (some may not be undoable).
+    Redo - Redo the last undone action (some may not be redoable).
+    Select All - Select all the text in the editor.
+    Select Paragraph - Select the paragraph at the current cursor postion.
+    Select Line - Select the line at the current cursor postion.
+    Select Word - Select the word at the current cursor postion.
+
+View Menu
+
+    Toolbar - Toggles display of the ToolBar.
+    Source - Toggles display of the Source window, where the HTML can be
+        observed and directly manipulated.
+
+Font Menu
+
+    Bold - Bold the selected text.
+    Italic - Italicise the selected text.
+    Underline - Underline the selected text.
+    Strike-through - Strike through the selected text.
+    Big - Increase the font size of the selected text.
+    Small - Decrease the font size of the selected text.
+    Superscript - Change the selected text to superscripted text.
+    Subscript - Change the selected text to subscripted text.
+    Monospaced - Render the select text in the Monospaced font.
+    Sans-serif - Render the select text in the Sans-serif font.
+    Serif - Render the select text in the Serif font.
+    Color Submenu
+        Aqua - Color the selected text aqua.
+        Black - Color the selected text black.
+        Blue - Color the selected text blue.
+        Fuschia - Color the selected text fuschia.
+        Gray - Color the selected text gray.
+        Green - Color the selected text green.
+        Lime - Color the selected text lime.
+        Maroon - Color the selected text maroon.
+        Navy - Color the selected text navy.
+        Olive - Color the selected text olive.
+        Purple - Color the selected text purple.
+        Red - Color the selected text red.
+        Silver - Color the selected text silver.
+        Teal - Color the selected text teal.
+        White - Color the selected text white.
+        Yellow - Color the selected text yellow.
+
+Format Menu
+
+    Align Submenu
+        Align Left - Left align the selected text (may include unselected text
+            that is part of the element)
+        Align Center - Center align the selected text (same proviso as Left)
+        Align Right - Right align the selected text (same proviso as Left)
+        Align Justified - Justify the selected text (same proviso as Left)
+    Heading Submenu
+        Heading 1 - Render the selected text in the HTML <H1> style.
+        Heading 2 - Render the selected text in the HTML <H2> style.
+        Heading 3 - Render the selected text in the HTML <H3> style.
+        Heading 4 - Render the selected text in the HTML <H4> style.
+        Heading 5 - Render the selected text in the HTML <H5> style.
+        Heading 6 - Render the selected text in the HTML <H6> style.
+    Unordered List - Convert the selected text to an unordered (bulleted)
+        list. New list items are created at each paragraph mark in the text.
+    Ordered List - Convert the selected text to an ordered (numeric)
+        list. New list items are created at each paragraph mark in the text.
+    List Item - Convert the selected text to a list item (will create an
+        enclosing unordered list if not part of a defined list).
+    Blockquote - Place the selected text inside BLOCKQUOTE tags.
+    Pre - Place the selected text inside PRE (preformat) tags.
+    Span - Place the selected text inside SPAN tags.
+    Clear Format - Remove markup from elements.
+
+Insert Menu
+
+    Anchor - Convert the selected text to a hyperlink after specifying the URL
+        in the pop-up dialog
+    Break - Insert an HTML break <BR> element
+    Nonbreaking Space - Inst an HTML non-breaking space (&nbsp;) metacharacter
+    Horizontal Rule - Insert an HTML horizontal rule <HR> element
+    Insert Local Image - Insert an image from file chooser pop-up
+    Insert Image From Server - Insert an image from server (requires server
+        image app to be runnning)
+
+Table Menu
+
+    Table - Insert a table based on settings in pop-up
+    Insert Row - Insert a row in the current table
+    Insert Column - Insert a column in the current table
+    Delete Row - Delete a row in the current table
+    Delete Column - Delete a column in the current table
+
+Forms Menu
+
+    Insert Form - Add the surrounding FORM tags for an HTML form
+    Text Field - Insert an HTML Text Field <INPUT TYPE="text">
+    Text Area - Insert an HTML Text Area <TEXTAREA></TEXTAREA>
+    Checkbox - Insert an HTML Checkbox <INPUT TYPE="checkbox">
+    Text Field - Insert an HTML Radio Button <INPUT TYPE="radio">
+    Button - Insert an HTML Button <INPUT TYPE="button"> (NON-RENDERING!)
+    Submit Button - Insert an HTML Submit Button <INPUT TYPE="submit">
+    Resest Button - Insert an HTML Reset Button <INPUT TYPE="reset">
+
+Help Menu
+
+    About - Displays the Ekit About information dialog
+
+Debug Menu
+
+    Describe Doc - Describe the document nodes to the console window
+    Describe CSS - Describe the stylesheet properties to the console window
+    What Tags? - List the node tags applied to the element under the cursor
+
+
+VERSION HISTORY
+--------------------------
+
+0.1  (08/08/2000)
+    - initial creation
+0.2  (08/24/2000)
+    - added tag attribute management
+    - added anchors
+    - cleaned up menu actions
+0.3  (08/30/2000)
+    - added appName & currentFile
+    - added Save menu item
+    - added updateTitle method
+    - changed to only empty constructor
+    - added refreshOnUpdate() optional refresh code
+0.4  (08/31/2000)
+    - added table insertion (experimental)
+    - added image insertion (experimental)
+0.45 (09/05/2000)
+    - added list formatting
+    - added break insertion
+    - added horizontal rule insertion
+    - added purgeUndos() convenience method for resetting the UndoManager
+    - changed "load" commands to "open" commands
+      (more in line with current application conventions)
+    - merged some menus so that they no longer build an explicit JMenuItem
+      (sacrifices some readability for object allocation improvements)
+0.5  (09/18/2000)
+    - added CSS support
+    - moved calls to JFileChooser to a reusable method
+    - moved "debug" types of functions to their own menu
+    - renamed the "Styles" menu "Format", so as not to be confused with
+      StyleSheet Styles
+0.6  (09/29/2000)
+    - added optional ToolBar
+    - added table row, table cell, and table-within-table insertion
+    - vastly improved break & horizontal rule insertion
+    - allow pre-loading of HTML document and CSS stylesheet from command line
+    - centralized exception handling
+    - fixed getFileFromChooser method to correctly display OPEN/SAVE dialogs
+    - now exists as a JAR file
+0.7  (11/03/2000)
+    - added Source window for viewing/editing HTML tags
+    - added Shift-Return insertion of BR tags
+0.8  (05/05/2001)
+    - added JButtonNoFocus inner class to keep toolbar buttons from taking
+      focus from editor canvas
+    - added JToggleButtonNoFocus inner class for toolbar elements that indicate
+      toggle-state features (such as View Source)
+0.9 (01/06/2002)
+    - added mnemonics for menu items (this also removed need for KeyListener)
+    - added View menu
+    - added Help menu
+    - added table settings dialog
+    - added Internationalization capabilities
+    - added language files for Italian, German, Spanish, Portuguese, and
+      Slovenian
+    - fixed lack of repaint after cancelling "Open Stylesheet"
+    - Debug menu now optional, defaults to OFF
+    - moved View Source and Edit Mode to new View menu
+0.9a (02/02/2002)
+    - added image rendering & image selector
+    - image types supported : JPEG, GIF, & PNG
+    - added fix for dealing with HTML character encoding issue
+0.9b (03/08/2002)
+    - added CSS style selector
+    - added more standard HTML tags : STRONG, EM, BLOCKQUOTE, PRE, and TT
+0.9c (03/23/2002)
+    - added Search menu and Find/Replace functions
+    - added auto-bulleted lists
+    - added warning dialog for actions that fail
+    - split-pane divider now remembers its position
+    - changed and consolidated some menus
+    - altered "Save Body" method to work more as expected
+0.9d (09/24/2002)
+    - added language files for French and Norwegian
+    - broke out inner classes to separate component classes
+    - added EkitCallback class to allow easier access by shared components
+    - much improved Anchor handling and formatting
+    - changes to get app to work on JDK 1.4
+0.9e (10/26/2002)
+    - Ekit split into core (EkitCore) and shell (Ekit, EkitApplet) classes
+    - added language files for Finnish and Dutch
+    - added support for HTML forms and form elements
+    - added <STRIKE> tag support
+    - font familes and <HR> insertion now through inherent editor actions
+    - "Insert Table Row" now inserts the correct number of cells
+    - added generic PropertiesDialog
+    - SimpleInfoDialog auto-centers and allows different dialog types
+    - added calls to build semi-custom menus and toolbars
+    - removed EkitCallback (obsolesced by EkitCore)
+    - Change of license to LGPL (see ABOUT LICENSE section)
+0.9f (11/25/2002)
+    - optional integration of Jazzy spellchecker
+    - addition of font selector
+    - greater menu customization
+0.9g (5/5/2003)
+    - can load and save documents in Base64 encoded format
+    - bulleted lists now create new entries upon hitting ENTER
+    - added color picker to font selector
+    - support for access to the System Clipboard
+    - support for loading images from server via servlet
+    - added dispose() method to core
+    - added more insert and delete options for tables
+    - tables now have their own menu and better functionality
+    - fixed problem with IMG tag SRC URLs containing spaces
+    - fixed the getDocumentBody error where the contents did not reflect
+          the current document
+    - fixed the known memory/resource leaks caused by the SpellChecker
+    - added language files for Spanish (Mexican), Hungarian and Chinese
+
+NOTE: The following items work in Ekit but not yet in EkitApplet, due to the
+applet security model:
+
+    - Insert Image (Images referenced via a URL should work, though)
+    - Copy & Paste from system clipboard
+    - Access of local files
+
+We are looking into ways to make these features available. The probable
+solution will be to obtain a security certificate.
+
+
+CONTRIBUTORS
+--------------------------
+
+Thanks to the many people who have downloaded and used Ekit, as well as
+providing valuable feedback. The following people have made additional
+contributions to Ekit. (List in is chronological order of contribution.)
+
+Yaodong Liu (yaodongliu@yahoo.com)
+    - CSS Support Code
+    - HTML Insertion Support Code
+Gyoergy Magoss (GYOERGY.MAGOSS@bhf-bank.com)
+    - Table Support Code
+Oliver Moser (omoser@dkf.de)
+    - HTML Insertion Support Code
+Michael Goldberg (MGoldberg@yet2.com)
+    - README Support
+Cecile Rostaing (cecile.rostaing@free.fr)
+    - Feature Suggestions
+Thomas Gauweiler (gauweiler@fzi.de)
+    - EkitAppletDemo2.html & ShowAppletOutput.php demo files
+Frits Jalvingh (jal@grimor.com)
+    - Correct image rendering and character encoding support
+    - CSS Styles Selector
+    - Original ExtendedHTMLEditorKit & RelativeImageView classes
+    - Original ImageFileChooser & ImageFileChooserPreview classes
+Ruud Noordermeer (ruud.noordermeer@back2front.nl)
+    - Fix for split-pane rendering issue in EkitApplet
+Mindaugas Idzelis (aim4min@users.sourceforge.net)
+    - Provided the excellent Jazzy spellchecker
+Raymond Penners (dotsphinx@users.sourceforge.net)
+    - Fix for IMG tag SRC URLs containing spaces
+Steve Birmingham (steve.birmingham@c3bgroup.com)
+    - Server image support classes and methods
+    - Color picker code in font dialog
+    - Numerous bug fixes, including the dispose() for the SpellChecker
+Rafael Cieplinski (cieplinski@web.de)
+    - Better auto-bulleting function
+    - Improved table handling
+    - Original HTMLUtilities class
+Nico Mack (nico.mack@mmp.lu)
+    - System clipboard access code
+    - Other bug fixes
+
+
+TRANSLATIONS
+--------------------------
+
+Thanks also to the people who volunteered to translate Ekit into their
+languages. The following people have made translations available.
+(List in is chronological order of contribution. Any current errors in the
+language files are most likely do to my own attempts to add new terms to them,
+and I appreciate receiving any corrections.)
+
+Nick Schwendener (nschwendener@vtxnet.ch)
+    - Italian
+        LanguageResources_it_CH.properties
+        LanguageResources_it_IT.properties
+Gyoergy Magoss (GYOERGY.MAGOSS@bhf-bank.com)
+    - German
+        LanguageResources_de_DE.properties
+Jesus Escanero (jescanero@yahoo.es)
+    - Spanish
+        LanguageResources_es_ES.properties
+Fernando Luiz (responsavel2@hotmail.com)
+    - Portuguese
+        LanguageResources_pt_BR.properties
+        LanguageResources_pt_PT.properties
+Jernej Vicic (jernej@activetools.si)
+    - Slovenian
+        LanguageResources_sl_SI.properties
+Gerald Estadieu (gerald.estadieu@cem-macau.com)
+    - French
+        LanguageResources_fr_FR.properties
+Anders Bjorvand (anders@kommunion.no)
+    - Norwegian
+        LanguageResources_no_NO.properties
+Vesa Kotilainen (vesa.kotilainen@sonera.com)
+    - Finnish
+        LanguageResources_fi_FI.properties
+Mark de Haan (mark@starwave.nl)
+    - Dutch
+        LanguageResources_nl_NL.properties
+Samuel Dmaz
+    - Spanish (Mexican)
+        LanguageResources_es_MX.properties
+Tamás Érdfalvi (devnull@eagent.hu)
+    - Hungarian
+        LanguageResources_hu_HU.properties
+Yang Yu (yangyu@users.sourceforge.net)
+    - Chinese
+        LanguageResources_zh_CN.properties
diff --git a/ekit/com/hexidec/ekit/TreePilot.properties b/ekit/com/hexidec/ekit/TreePilot.properties
new file mode 100644 (file)
index 0000000..c54b6df
--- /dev/null
@@ -0,0 +1,2 @@
+ValidFileExtensions=.doc:.htm:.pdf:.txt\r
+ValidImageExtensions=.bmp:.emf:.gif:.jpg:.pcx:.psp:.tif:.tiff:.wmf:.wpg\r
diff --git a/ekit/com/hexidec/ekit/action/CustomAction.java b/ekit/com/hexidec/ekit/action/CustomAction.java
new file mode 100644 (file)
index 0000000..0ed45f4
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+GNU Lesser General Public License
+
+CustomAction
+Copyright (C) 2000-2003 Howard Kistler
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+package com.hexidec.ekit.action;
+
+import java.awt.Color;
+import java.awt.event.ActionEvent;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import javax.swing.JColorChooser;
+import javax.swing.JTextPane;
+import javax.swing.text.SimpleAttributeSet;
+import javax.swing.text.StyledEditorKit;
+import javax.swing.text.html.HTML;
+
+import com.hexidec.ekit.EkitCore;
+import com.hexidec.ekit.component.FontSelectorDialog;
+import com.hexidec.ekit.component.SimpleInfoDialog;
+import com.hexidec.ekit.component.UserInputAnchorDialog;
+
+import com.hexidec.util.Translatrix;
+
+/** Class for implementing custom HTML insertion actions
+*/
+public class CustomAction extends StyledEditorKit.StyledTextAction
+{
+       protected EkitCore parentEkit;
+       private   HTML.Tag htmlTag;
+       private   Hashtable htmlAttribs;
+
+       public CustomAction(EkitCore ekit, String actionName, HTML.Tag inTag, Hashtable attribs)
+       {
+               super(actionName);
+               parentEkit  = ekit;
+               htmlTag     = inTag;
+               htmlAttribs = attribs;
+       }
+
+       public CustomAction(EkitCore ekit, String actionName, HTML.Tag inTag)
+       {
+               this(ekit, actionName, inTag, new Hashtable());
+       }
+
+       public void actionPerformed(ActionEvent ae)
+       {
+               Hashtable htmlAttribs2 = new Hashtable();
+               JTextPane parentTextPane = parentEkit.getTextPane();
+               String selText = parentTextPane.getSelectedText();
+               int textLength = -1;
+               if(selText != null)
+               {
+                       textLength = selText.length();
+               }
+               if(selText == null || textLength < 1)
+               {
+                       SimpleInfoDialog sidWarn = new SimpleInfoDialog(parentEkit.getFrame(), "", true, Translatrix.getTranslationString("ErrorNoTextSelected"), SimpleInfoDialog.ERROR);
+               }
+               else
+               {
+                       int caretOffset = parentTextPane.getSelectionStart();
+                       int internalTextLength = selText.length();
+                       String currentAnchor = "";
+                       // Somewhat ham-fisted code to obtain the first HREF in the selected text,
+                       // which (if found) is passed to the URL HREF request dialog.
+                       if(htmlTag.toString().equals(HTML.Tag.A.toString()))
+                       {
+                               SimpleAttributeSet sasText = null;
+                               for(int i = caretOffset; i < caretOffset + internalTextLength; i++)
+                               {
+                                       parentTextPane.select(i, i + 1);
+                                       sasText = new SimpleAttributeSet(parentTextPane.getCharacterAttributes());
+                                       Enumeration attribEntries1 = sasText.getAttributeNames();
+                                       while(attribEntries1.hasMoreElements() && currentAnchor.equals(""))
+                                       {
+                                               Object entryKey   = attribEntries1.nextElement();
+                                               Object entryValue = sasText.getAttribute(entryKey);
+                                               if(entryKey.toString().equals(HTML.Tag.A.toString()))
+                                               {
+                                                       if(entryValue instanceof SimpleAttributeSet)
+                                                       {
+                                                               Enumeration subAttributes = ((SimpleAttributeSet)entryValue).getAttributeNames();
+                                                               while(subAttributes.hasMoreElements() && currentAnchor.equals(""))
+                                                               {
+                                                                       Object subKey = subAttributes.nextElement();
+                                                                       if(subKey.toString().toLowerCase().equals("href"))
+                                                                       {
+                                                                               currentAnchor = ((SimpleAttributeSet)entryValue).getAttribute(subKey).toString();
+                                                                               break;
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                       }
+                                       if(!currentAnchor.equals("")) { break; }
+                               }
+                       }
+
+                       parentTextPane.select(caretOffset, caretOffset + internalTextLength);
+                       SimpleAttributeSet sasTag  = new SimpleAttributeSet();
+                       SimpleAttributeSet sasAttr = new SimpleAttributeSet();
+                       if(htmlTag.toString().equals(HTML.Tag.A.toString()))
+                       {
+                               if(!htmlAttribs.containsKey("href"))
+                               {
+                                       UserInputAnchorDialog uidInput = new UserInputAnchorDialog(parentEkit, Translatrix.getTranslationString("AnchorDialogTitle"), true, currentAnchor);
+                                       String newAnchor = uidInput.getInputText();
+                                       uidInput.dispose();
+                                       if(newAnchor != null)
+                                       {
+                                               htmlAttribs2.put("href", newAnchor);
+                                       }
+                                       else
+                                       {
+                                               parentEkit.repaint();
+                                               return;
+                                       }
+                               }
+                       }
+                       else if(htmlTag.toString().equals(HTML.Tag.FONT.toString()))
+                       {
+                               if(htmlAttribs.containsKey("face"))
+                               {
+                                       FontSelectorDialog fsdInput = new FontSelectorDialog(parentEkit.getFrame(), Translatrix.getTranslationString("FontDialogTitle"), true, "face", parentTextPane.getSelectedText());
+                                       String newFace = fsdInput.getFontName();
+                                       if(newFace != null)
+                                       {
+                                               htmlAttribs2.put("face", newFace);
+                                       }
+                                       else
+                                       {
+                                               parentEkit.repaint();
+                                               return;
+                                       }
+                               }
+
+                               else if(htmlAttribs.containsKey("size"))
+                               {
+                                       htmlAttribs2.put("size", new String((String)htmlAttribs.get("size")));
+                               }
+
+                               else if(htmlAttribs.containsKey("color"))
+                               {
+                                       Color color = new JColorChooser().showDialog(parentEkit.getFrame(),"Choose Text Color",Color.black);
+                                     if(color != null)
+                                       {
+                                               String redHex = Integer.toHexString(color.getRed());
+                                               if(redHex.length() < 2)
+                                               {
+                                                       redHex = "0" + redHex;
+                                               }
+                                               String greenHex = Integer.toHexString(color.getGreen());
+                                               if(greenHex.length() < 2)
+                                               {
+                                                       greenHex = "0" + greenHex;
+                                               }
+                                               String blueHex = Integer.toHexString(color.getBlue());
+                                               if(blueHex.length() < 2)
+                                               {
+                                                       blueHex = "0" + blueHex;
+                                               }
+                                               htmlAttribs2.put("color", "#" + redHex + greenHex + blueHex);
+                                       }
+                                       else
+                                       {
+                                               parentEkit.repaint();
+                                               return;
+                                       }
+                               }
+
+                       }
+
+                       if(htmlAttribs2.size() > 0)
+                       {
+                               Enumeration attribEntries = htmlAttribs2.keys();
+                               while(attribEntries.hasMoreElements())
+                               {
+                                       Object entryKey   = attribEntries.nextElement();
+                                       Object entryValue = htmlAttribs2.get(entryKey);
+                                       sasAttr.addAttribute(entryKey, entryValue);
+                               }
+                               sasTag.addAttribute(htmlTag, sasAttr);
+                               parentTextPane.setCharacterAttributes(sasTag, false);
+                               parentEkit.refreshOnUpdate();
+                       }
+                       parentTextPane.select(caretOffset, caretOffset + internalTextLength);
+                       parentTextPane.requestFocus();
+               }
+       }
+}
+
diff --git a/ekit/com/hexidec/ekit/action/FormatAction.java b/ekit/com/hexidec/ekit/action/FormatAction.java
new file mode 100644 (file)
index 0000000..2e679ac
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+GNU Lesser General Public License
+
+FormatAction
+Copyright (C) 2000-2003 Howard Kistler
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+package com.hexidec.ekit.action;
+
+import java.awt.event.ActionEvent;
+import javax.swing.JTextPane;
+import javax.swing.text.SimpleAttributeSet;
+import javax.swing.text.StyledEditorKit;
+import javax.swing.text.html.HTML;
+
+import com.hexidec.ekit.EkitCore;
+import com.hexidec.ekit.component.*;
+
+import com.hexidec.util.Translatrix;
+
+/** Class for implementing HTML format actions
+ * (NOTE : Does not toggle. User must use the "Clear Format" option to remove formatting correctly.)
+ */
+public class FormatAction extends StyledEditorKit.StyledTextAction
+{
+       protected EkitCore parentEkit;
+       HTML.Tag htmlTag;
+
+       public FormatAction(EkitCore ekit, String actionName, HTML.Tag inTag)
+       {
+               super(actionName);
+               parentEkit = ekit;
+               htmlTag    = inTag;
+       }
+
+       public void actionPerformed(ActionEvent ae)
+       {
+               JTextPane parentTextPane = parentEkit.getTextPane();
+               String selText = parentTextPane.getSelectedText();
+               int textLength = -1;
+               if(selText != null)
+               {
+                       textLength = selText.length();
+               }
+               if(selText == null || textLength < 1)
+               {
+                       SimpleInfoDialog sidWarn = new SimpleInfoDialog(parentEkit.getFrame(), "", true, Translatrix.getTranslationString("ErrorNoTextSelected"), SimpleInfoDialog.ERROR);
+               }
+               else
+               {
+                       SimpleAttributeSet sasText = new SimpleAttributeSet(parentTextPane.getCharacterAttributes());
+                       sasText.addAttribute(htmlTag, new SimpleAttributeSet());
+                       int caretOffset = parentTextPane.getSelectionStart();
+                       parentTextPane.select(caretOffset, caretOffset + textLength);
+                       parentTextPane.setCharacterAttributes(sasText, false);
+                       parentEkit.refreshOnUpdate();
+                       parentTextPane.select(caretOffset, caretOffset + textLength);
+               }
+       }
+}
+
diff --git a/ekit/com/hexidec/ekit/action/ListAutomationAction.java b/ekit/com/hexidec/ekit/action/ListAutomationAction.java
new file mode 100644 (file)
index 0000000..5bc4a72
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+GNU Lesser General Public License
+
+ListAutomationAction
+Copyright (C) 2000-2003 Howard Kistler
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+package com.hexidec.ekit.action;
+
+import java.awt.event.ActionEvent;
+import java.util.StringTokenizer;
+import javax.swing.JEditorPane;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.html.HTML;
+import javax.swing.text.html.HTMLDocument;
+import javax.swing.text.html.HTMLEditorKit;
+
+import com.hexidec.ekit.EkitCore;
+import com.hexidec.ekit.component.*;
+
+import com.hexidec.util.Translatrix;
+
+/** Class for automatically creating bulleted lists from selected text
+  */
+public class ListAutomationAction extends HTMLEditorKit.InsertHTMLTextAction
+{
+       protected EkitCore parentEkit;
+       private HTML.Tag baseTag;
+       private String sListType;
+       private HTMLUtilities htmlUtilities;
+
+       public ListAutomationAction(EkitCore ekit, String sLabel, HTML.Tag listType)
+       {
+               super(sLabel, "", listType, HTML.Tag.LI);
+               parentEkit = ekit;
+               baseTag    = listType;
+               htmlUtilities = new HTMLUtilities(ekit);
+       }
+
+       public void actionPerformed(ActionEvent ae)
+       {
+               try
+               {
+                       JEditorPane jepEditor = (JEditorPane)(parentEkit.getTextPane());
+                       String selTextBase = jepEditor.getSelectedText();
+                       int textLength = -1;
+                       if(selTextBase != null)
+                       {
+                               textLength = selTextBase.length();
+                       }
+                       if(selTextBase == null || textLength < 1)
+                       {
+                               int pos = parentEkit.getCaretPosition();
+                               parentEkit.setCaretPosition(pos);
+                               if(ae.getActionCommand() != "newListPoint")
+                               {
+                                       if(htmlUtilities.checkParentsTag(HTML.Tag.OL) || htmlUtilities.checkParentsTag(HTML.Tag.UL))
+                                       {
+                                               new SimpleInfoDialog(parentEkit.getFrame(), Translatrix.getTranslationString("Error"), true, Translatrix.getTranslationString("ErrorNestedListsNotSupported"));
+                                               return;
+                                       }
+                               }
+                               String sListType = (baseTag == HTML.Tag.OL ? "ol" : "ul");
+                               StringBuffer sbNew = new StringBuffer();
+                               if(htmlUtilities.checkParentsTag(baseTag))
+                               {
+                                       sbNew.append("<li></li>");
+                                       insertHTML(parentEkit.getTextPane(), parentEkit.getExtendedHtmlDoc(), parentEkit.getTextPane().getCaretPosition(), sbNew.toString(), 0, 0, HTML.Tag.LI);
+                               }
+                               else
+                               {
+                                       sbNew.append("<" + sListType + "><li></li></" + sListType + "><p>&nbsp;</p>");
+                                       insertHTML(parentEkit.getTextPane(), parentEkit.getExtendedHtmlDoc(), parentEkit.getTextPane().getCaretPosition(), sbNew.toString(), 0, 0, (sListType.equals("ol") ? HTML.Tag.OL : HTML.Tag.UL));
+                               }
+                               parentEkit.refreshOnUpdate();
+                       }
+                       else
+                       {
+                               String sListType = (baseTag == HTML.Tag.OL ? "ol" : "ul");
+                               HTMLDocument htmlDoc = (HTMLDocument)(jepEditor.getDocument());
+                               int iStart = jepEditor.getSelectionStart();
+                               int iEnd   = jepEditor.getSelectionEnd();
+                               String selText = htmlDoc.getText(iStart, iEnd - iStart);
+                               StringBuffer sbNew = new StringBuffer();
+                               String sToken = ((selText.indexOf("\r") > -1) ? "\r" : "\n");
+                               StringTokenizer stTokenizer = new StringTokenizer(selText, sToken);
+                               sbNew.append("<" + sListType + ">");
+                               while(stTokenizer.hasMoreTokens())
+                               {
+                                       sbNew.append("<li>");
+                                       sbNew.append(stTokenizer.nextToken());
+                                       sbNew.append("</li>");
+                               }
+                               sbNew.append("</" + sListType + "><p>&nbsp;</p>");
+                               htmlDoc.remove(iStart, iEnd - iStart);
+                               insertHTML(jepEditor, htmlDoc, iStart, sbNew.toString(), 1, 1, null);
+                       }
+               }
+               catch (BadLocationException ble) {}
+       }
+}
\ No newline at end of file
diff --git a/ekit/com/hexidec/ekit/action/StylesAction.java b/ekit/com/hexidec/ekit/action/StylesAction.java
new file mode 100644 (file)
index 0000000..1f6657b
--- /dev/null
@@ -0,0 +1,77 @@
+/*\r
+GNU Lesser General Public License\r
+\r
+StylesAction\r
+Copyright (C) 2000-2003 Howard Kistler\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+*/\r
+\r
+package com.hexidec.ekit.action;\r
+\r
+import java.awt.event.ActionEvent;\r
+import javax.swing.JComboBox;\r
+import javax.swing.JEditorPane;\r
+import javax.swing.text.MutableAttributeSet;\r
+import javax.swing.text.SimpleAttributeSet;\r
+import javax.swing.text.StyledEditorKit;\r
+import javax.swing.text.html.HTML;\r
+import javax.swing.text.html.HTMLEditorKit;\r
+\r
+import com.hexidec.util.Translatrix;\r
+\r
+/** Class for handling CSS style events\r
+  */\r
+public class StylesAction extends StyledEditorKit.StyledTextAction\r
+{\r
+\r
+       JComboBox parent;\r
+\r
+       public StylesAction(JComboBox myParent)\r
+       {\r
+               super("css-style");\r
+               parent = myParent;\r
+       }\r
+\r
+       public void actionPerformed(ActionEvent e)\r
+       {\r
+               if(!(this.isEnabled()))\r
+               {\r
+                       return;\r
+               }\r
+               JEditorPane editor = getEditor(e);\r
+               if(editor != null)\r
+               {\r
+                       String stylename = (String)(parent.getSelectedItem());\r
+                       if(stylename == null)\r
+                       {\r
+                               return;\r
+                       }\r
+                       else if(stylename.equals(Translatrix.getTranslationString("NoCSSStyle")))\r
+                       {\r
+                               return;\r
+                       }\r
+                       boolean replace = false;\r
+                       MutableAttributeSet     attr = null;\r
+                       SimpleAttributeSet cls = new SimpleAttributeSet();\r
+                       cls.addAttribute(HTML.Attribute.CLASS, stylename);\r
+                       attr = new SimpleAttributeSet();\r
+                       attr.addAttribute(HTML.Tag.FONT, cls);\r
+                       MutableAttributeSet inattr = ((HTMLEditorKit)(editor.getEditorKitForContentType("text/html"))).getInputAttributes();\r
+                       inattr.addAttributes(attr);\r
+                       setCharacterAttributes(editor, attr, replace);\r
+               }\r
+       }\r
+}\r
diff --git a/ekit/com/hexidec/ekit/component/ExtendedHTMLDocument.java b/ekit/com/hexidec/ekit/component/ExtendedHTMLDocument.java
new file mode 100644 (file)
index 0000000..2c016db
--- /dev/null
@@ -0,0 +1,106 @@
+package com.hexidec.ekit.component;\r
+\r
+import javax.swing.text.html.HTMLDocument;\r
+import javax.swing.text.Element;\r
+import javax.swing.text.AttributeSet;\r
+import javax.swing.text.MutableAttributeSet;\r
+import javax.swing.text.AbstractDocument;\r
+import javax.swing.text.BadLocationException;\r
+import javax.swing.undo.UndoableEdit;\r
+import javax.swing.text.html.StyleSheet;\r
+import javax.swing.text.html.HTML;\r
+import javax.swing.text.AbstractDocument.BranchElement;\r
+import java.util.Enumeration;\r
+import javax.swing.event.DocumentEvent;\r
+import javax.swing.event.UndoableEditEvent;\r
+\r
+public class ExtendedHTMLDocument\r
+    extends HTMLDocument {\r
+\r
+  public ExtendedHTMLDocument() {\r
+\r
+  }\r
+\r
+  public ExtendedHTMLDocument(AbstractDocument.Content c, StyleSheet styles) {\r
+    super(c, styles);\r
+  }\r
+\r
+  public ExtendedHTMLDocument(StyleSheet styles) {\r
+    super(styles);\r
+  }\r
+\r
+//-------------------------------------------------------------------------------------\r
+\r
+\r
+/**\r
+ *\r
+ * Überschreibt die Attribute des Elements.\r
+ *\r
+ * @param e Element bei dem die Attribute geändert werden sollen\r
+ * @param a AttributeSet mit den neuen Attributen\r
+ * @param tag Angabe was für ein Tag das Element ist\r
+ */\r
+  public void replaceAttributes(Element e, AttributeSet a, HTML.Tag tag) {\r
+    if( (e != null) && (a != null)) {\r
+      try {\r
+       writeLock();\r
+       int start = e.getStartOffset();\r
+       DefaultDocumentEvent changes = new DefaultDocumentEvent(start,\r
+           e.getEndOffset() - start, DocumentEvent.EventType.CHANGE);\r
+       AttributeSet sCopy = a.copyAttributes();\r
+       changes.addEdit(new AttributeUndoableEdit(e, sCopy, false));\r
+       MutableAttributeSet attr = (MutableAttributeSet) e.getAttributes();\r
+       Enumeration aNames = attr.getAttributeNames();\r
+       Object value;\r
+       Object aName;\r
+       while (aNames.hasMoreElements()) {\r
+         aName = aNames.nextElement();\r
+         value = attr.getAttribute(aName);\r
+         if(value != null && !value.toString().equalsIgnoreCase(tag.toString())) {\r
+           attr.removeAttribute(aName);\r
+         }\r
+       }\r
+       attr.addAttributes(a);\r
+       changes.end();\r
+       fireChangedUpdate(changes);\r
+       fireUndoableEditUpdate(new UndoableEditEvent(this, changes));\r
+      }\r
+      finally {\r
+       writeUnlock();\r
+      }\r
+    }\r
+  }\r
+\r
+\r
+  public void removeElements(Element e, int index, int count) throws\r
+      BadLocationException {\r
+    writeLock();\r
+    int start = e.getElement(index).getStartOffset();\r
+    int end = e.getElement(index + count - 1).getEndOffset();\r
+    try {\r
+      Element[] removed = new Element[count];\r
+      Element[] added = new Element[0];\r
+      for (int counter = 0; counter < count; counter++) {\r
+       removed[counter] = e.getElement(counter + index);\r
+      }\r
+      DefaultDocumentEvent dde = new DefaultDocumentEvent(\r
+         start, end - start, DocumentEvent.EventType.REMOVE);\r
+      ( (AbstractDocument.BranchElement) e).replace(index, removed.length,\r
+         added);\r
+      dde.addEdit(new ElementEdit(e, index, removed, added));\r
+      UndoableEdit u = getContent().remove(start, end - start);\r
+      if(u != null) {\r
+       dde.addEdit(u);\r
+      }\r
+      postRemoveUpdate(dde);\r
+      dde.end();\r
+      fireRemoveUpdate(dde);\r
+      if(u != null) {\r
+       fireUndoableEditUpdate(new UndoableEditEvent(this, dde));\r
+      }\r
+    }\r
+    finally {\r
+      writeUnlock();\r
+    }\r
+  }\r
+}
\ No newline at end of file
diff --git a/ekit/com/hexidec/ekit/component/ExtendedHTMLEditorKit.java b/ekit/com/hexidec/ekit/component/ExtendedHTMLEditorKit.java
new file mode 100644 (file)
index 0000000..bb2b14a
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+GNU Lesser General Public License
+
+ExtendedHTMLEditorKit
+Copyright (C) 2001-2002  Frits Jalvingh & Howard Kistler
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+package com.hexidec.ekit.component;
+
+import javax.swing.text.Element;
+import javax.swing.text.StyleConstants;
+import javax.swing.text.View;
+import javax.swing.text.ViewFactory;
+import javax.swing.text.html.HTML;
+import javax.swing.text.html.HTMLEditorKit;
+
+/* WACKY GERMAN CODE */
+import com.hexidec.ekit.component.ExtendedHTMLDocument;
+import javax.swing.text.html.StyleSheet;
+import javax.swing.text.Document;
+
+/**
+  * This class extends HTMLEditorKit so that it can provide other renderer classes
+  * instead of the defaults. Most important is the part which renders relative
+  * image paths.
+  *
+  * @author <a href="mailto:jal@grimor.com">Frits Jalvingh</a>
+  * @version 1.0
+  */
+
+public class ExtendedHTMLEditorKit extends HTMLEditorKit
+{
+       /** Constructor
+         */
+       public ExtendedHTMLEditorKit()
+       {
+       }
+
+       /** Method for returning a ViewFactory which handles the image rendering.
+         */
+       public ViewFactory getViewFactory()
+       {
+               return new HTMLFactoryExtended();
+       }
+
+/* WACKY GERMAN CODE */
+       public Document createDefaultDocument() {
+         StyleSheet styles = getStyleSheet();
+         StyleSheet ss = new StyleSheet();
+         ss.addStyleSheet(styles);
+         ExtendedHTMLDocument doc = new ExtendedHTMLDocument(ss);
+         doc.setParser(getParser());
+         doc.setAsynchronousLoadPriority(4);
+         doc.setTokenThreshold(100);
+         return doc;
+       }
+
+/* Inner Classes --------------------------------------------- */
+
+       /** Class that replaces the default ViewFactory and supports
+         * the proper rendering of both URL-based and local images.
+         */
+       public static class HTMLFactoryExtended extends HTMLFactory implements ViewFactory
+       {
+               /** Constructor
+                 */
+               public HTMLFactoryExtended()
+               {
+               }
+
+               /** Method to handle IMG tags and
+                 * invoke the image loader.
+                 */
+               public View create(Element elem)
+               {
+                       Object obj = elem.getAttributes().getAttribute(StyleConstants.NameAttribute);
+                       if(obj instanceof HTML.Tag)
+                       {
+                               HTML.Tag tagType = (HTML.Tag)obj;
+                               if(tagType == HTML.Tag.IMG)
+                               {
+                                       return new RelativeImageView(elem);
+                               }
+                       }
+                       return super.create(elem);
+               }
+       }
+}
diff --git a/ekit/com/hexidec/ekit/component/FileDialog.java b/ekit/com/hexidec/ekit/component/FileDialog.java
new file mode 100644 (file)
index 0000000..7dd3b2f
--- /dev/null
@@ -0,0 +1,113 @@
+package com.hexidec.ekit.component;\r
+\r
+import com.hexidec.ekit.EkitCore;\r
+import java.awt.event.ActionListener;\r
+import java.awt.Container;\r
+import javax.swing.border.*;\r
+import javax.swing.BorderFactory;\r
+import javax.swing.BoxLayout;\r
+import javax.swing.event.ListSelectionListener;\r
+import javax.swing.event.ListSelectionEvent;\r
+import javax.swing.JButton;\r
+import javax.swing.JDialog;\r
+import javax.swing.JList;\r
+import javax.swing.JPanel;\r
+import javax.swing.JScrollPane;\r
+import javax.swing.ListSelectionModel;\r
+import javax.swing.SwingConstants;\r
+import javax.swing.WindowConstants;\r
+\r
+public class FileDialog extends JDialog implements ActionListener\r
+{\r
+       private EkitCore ParentEkit;\r
+       private JList FileList;\r
+       private String FileDir;\r
+       private String[]Files;\r
+       private String SelectedFile;\r
+\r
+       public FileDialog(EkitCore parentEkit, String fileDir, String[] fileList, String title, boolean modal)\r
+       {\r
+               super(parentEkit.getFrame(), title, modal);\r
+               FileDir = fileDir;\r
+               Files = fileList;\r
+               ParentEkit = parentEkit;\r
+               init();\r
+       }\r
+\r
+       public void actionPerformed(java.awt.event.ActionEvent e)\r
+       {\r
+               if(e.getActionCommand().equals("save"))\r
+               {\r
+                       hide();\r
+               }\r
+               else if(e.getActionCommand().equals("cancel"))\r
+               {\r
+                       SelectedFile = null;\r
+                       hide();\r
+               }\r
+       }\r
+\r
+       public void init()\r
+       {\r
+               SelectedFile="";\r
+               Container contentPane = getContentPane();\r
+               contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS));\r
+               setBounds(100,100,300,200);\r
+               setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE);\r
+\r
+               FileList = new JList(Files);\r
+               FileList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);\r
+               FileList.clearSelection();\r
+            ListSelectionModel lsm = FileList.getSelectionModel();\r
+\r
+               lsm.addListSelectionListener(new ListSelectionListener() \r
+               {\r
+                       public void valueChanged(ListSelectionEvent e)\r
+                       {\r
+                               if(!e.getValueIsAdjusting())\r
+                               {\r
+                                       ListSelectionModel sm = FileList.getSelectionModel();\r
+                                       if(!sm.isSelectionEmpty())\r
+                                       {\r
+                                               SelectedFile = Files[sm.getMinSelectionIndex()];\r
+                                       }\r
+                               }\r
+                       }\r
+                               \r
+               });\r
+\r
+               JScrollPane fileScrollPane = new JScrollPane(FileList);\r
+               fileScrollPane.setAlignmentX(LEFT_ALIGNMENT);\r
+               JPanel centerPanel = new JPanel();\r
+               centerPanel.setLayout(new BoxLayout(centerPanel, BoxLayout.X_AXIS));\r
+               centerPanel.add(fileScrollPane);\r
+               centerPanel.setBorder(BorderFactory.createTitledBorder("Files"));\r
+\r
+               JPanel buttonPanel= new JPanel();               \r
+               buttonPanel.setBorder(new SoftBevelBorder(BevelBorder.LOWERED));\r
+\r
+               JButton saveButton = new JButton("Accept");\r
+               saveButton.setActionCommand("save");\r
+               saveButton.addActionListener(this);\r
+               JButton cancelButton = new JButton("Cancel");\r
+               cancelButton.setActionCommand("cancel");\r
+               cancelButton.addActionListener(this);\r
+\r
+               buttonPanel.add(saveButton);\r
+               buttonPanel.add(cancelButton);\r
+\r
+               contentPane.add(centerPanel);\r
+               contentPane.add(buttonPanel);\r
+               setVisible(true);\r
+    }\r
+\r
+    public String getSelectedFile()\r
+    {\r
+         if(SelectedFile != null)\r
+         {\r
+               SelectedFile = FileDir + "/" + SelectedFile;\r
+         }\r
+         return SelectedFile;\r
+    }\r
+\r
+}\r
diff --git a/ekit/com/hexidec/ekit/component/FontSelectorDialog.java b/ekit/com/hexidec/ekit/component/FontSelectorDialog.java
new file mode 100644 (file)
index 0000000..616e11e
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+GNU Lesser General Public License
+
+FontSelectorDialog
+Copyright (C) 2003 Howard Kistler
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+package com.hexidec.ekit.component;
+
+import java.awt.Frame;
+import java.awt.GraphicsEnvironment;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.util.Vector;
+import javax.swing.JComboBox;
+import javax.swing.JDialog;
+import javax.swing.JOptionPane;
+import javax.swing.JTextPane;
+import javax.swing.text.html.HTMLDocument;
+import javax.swing.text.html.HTMLEditorKit;
+
+import com.hexidec.util.Translatrix;
+
+/** Class for providing a dialog that lets the user specify values for tag attributes
+  */
+public class FontSelectorDialog extends JDialog implements ItemListener
+{
+       private Vector vcFontnames = (Vector)null;
+       private final JComboBox jcmbFontlist;
+       private String fontName = new String();
+       private JOptionPane jOptionPane;
+       private final JTextPane jtpFontPreview;
+       private String defaultText;
+
+       public FontSelectorDialog(Frame parent, String title, boolean bModal, String attribName, String demoText)
+       {
+               super(parent, title, bModal);
+
+               if(demoText != null && demoText.length() > 0)
+               {
+                       if(demoText.length() > 24)
+                       {
+                               defaultText = demoText.substring(0, 24);
+                       }
+                       else
+                       {
+                               defaultText = demoText;
+                       }
+               }
+               else
+               {
+                       defaultText = "aAbBcCdDeEfFgGhH,.0123";
+               }
+
+               /* Obtain available fonts */
+               String[] fonts = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
+               vcFontnames = new Vector(fonts.length - 5);
+               for(int i = 0; i < fonts.length; i++)
+               {
+                       if(!fonts[i].equals("Dialog") && !fonts[i].equals("DialogInput") && !fonts[i].equals("Monospaced") && !fonts[i].equals("SansSerif") && !fonts[i].equals("Serif"))
+                       {
+                               vcFontnames.add(fonts[i]);
+                       }
+               }
+               jcmbFontlist = new JComboBox(vcFontnames);
+               jcmbFontlist.addItemListener(this);
+
+               jtpFontPreview = new JTextPane();
+               final HTMLEditorKit kitFontPreview = new HTMLEditorKit();
+               final HTMLDocument docFontPreview = (HTMLDocument)(kitFontPreview.createDefaultDocument());
+               jtpFontPreview.setEditorKit(kitFontPreview);
+               jtpFontPreview.setDocument(docFontPreview);
+               jtpFontPreview.setMargin(new Insets(4, 4, 4, 4));
+               jtpFontPreview.setBounds(0, 0, 120, 18);
+               jtpFontPreview.setText(getFontSampleString(defaultText));
+               Object[] panelContents = { attribName, jcmbFontlist, Translatrix.getTranslationString("FontSample"), jtpFontPreview };
+               final Object[] buttonLabels = { Translatrix.getTranslationString("DialogAccept"), Translatrix.getTranslationString("DialogCancel") };
+
+               jOptionPane = new JOptionPane(panelContents, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION, null, buttonLabels, buttonLabels[0]);
+               setContentPane(jOptionPane);
+               setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
+
+               addWindowListener(new WindowAdapter() {
+                       public void windowClosing(WindowEvent we)
+                       {
+                               jOptionPane.setValue(new Integer(JOptionPane.CLOSED_OPTION));
+                       }
+               });
+
+               jOptionPane.addPropertyChangeListener(new PropertyChangeListener() {
+                       public void propertyChange(PropertyChangeEvent e)
+                       {
+                               String prop = e.getPropertyName();
+                               if(isVisible() 
+                                       && (e.getSource() == jOptionPane)
+                                       && (prop.equals(JOptionPane.VALUE_PROPERTY) || prop.equals(JOptionPane.INPUT_VALUE_PROPERTY)))
+                               {
+                                       Object value = jOptionPane.getValue();
+                                       if(value == JOptionPane.UNINITIALIZED_VALUE)
+                                       {
+                                               return;
+                                       }
+                                       jOptionPane.setValue(JOptionPane.UNINITIALIZED_VALUE);
+                                       if(value.equals(buttonLabels[0]))
+                                       {
+                                               fontName = (String)(jcmbFontlist.getSelectedItem());
+                                               setVisible(false);
+                                       }
+                                       else
+                                       {
+                                               fontName = null;
+                                               setVisible(false);
+                                       }
+                               }
+                       }
+               });
+               this.pack();
+               this.show();
+       }
+
+       /* ItemListener method */
+       public void itemStateChanged(ItemEvent ie)
+       {
+               if(ie.getStateChange() == ItemEvent.SELECTED)
+               {
+                       jtpFontPreview.setText(getFontSampleString(defaultText));
+               }
+       }
+
+       public FontSelectorDialog(Frame parent, String title, boolean bModal, String attribName)
+       {
+               this(parent, title, bModal, attribName, "");
+       }
+
+       public String getFontName()
+       {
+               return fontName;
+       }
+
+       private String getFontSampleString(String demoText)
+       {
+               return "<HTML><BODY><FONT FACE=" + '"' + jcmbFontlist.getSelectedItem() + '"' + ">" + demoText + "</FONT></BODY></HTML>";
+       }
+
+}
+
diff --git a/ekit/com/hexidec/ekit/component/HTMLUtilities.java b/ekit/com/hexidec/ekit/component/HTMLUtilities.java
new file mode 100644 (file)
index 0000000..6298488
--- /dev/null
@@ -0,0 +1,492 @@
+/*\r
+GNU Lesser General Public License\r
+\r
+HTMLUtilities - Special Utility Functions For Ekit\r
+Copyright (C) 2003 Rafael Cieplinski, modified by Howard Kistler\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+*/\r
+\r
+package com.hexidec.ekit.component;\r
+\r
+import java.io.*;\r
+import java.lang.reflect.*;\r
+import java.util.*;\r
+import javax.swing.*;\r
+import javax.swing.text.*;\r
+import javax.swing.text.html.*;\r
+\r
+import com.hexidec.ekit.EkitCore;\r
+import com.hexidec.ekit.component.*;\r
+\r
+public class HTMLUtilities\r
+{\r
+       EkitCore parent;\r
+       Hashtable tags = new Hashtable();\r
+\r
+       public HTMLUtilities(EkitCore newParent)\r
+       {\r
+               parent = newParent;\r
+               HTML.Tag[] tagList = HTML.getAllTags();\r
+               for(int i = 0; i < tagList.length; i++)\r
+               {\r
+                       tags.put(tagList[i].toString(), tagList[i]);\r
+               }\r
+/*\r
+               HTML.Tag classTag = new HTML.Tag();\r
+               Field[] fields = classTag.getClass().getDeclaredFields();\r
+               for(int i = 0; i < fields.length; i++)\r
+               {\r
+                       try\r
+                       {\r
+                               System.out.println("Adding " + (String)fields[i].get(null).toString() + " => " + (HTML.Tag)fields[i].get(null));\r
+                               tags.put((String)fields[i].get(null).toString(), (HTML.Tag)fields[i].get(null));\r
+                       }\r
+                       catch (IllegalAccessException iae)\r
+                       {\r
+                       }\r
+               }\r
+*/\r
+       }\r
+\r
+       /** Diese Methode fügt durch String-Manipulation in jtpSource\r
+         * ein neues Listenelement hinzu, content ist dabei der Text der in dem neuen\r
+         * Element stehen soll\r
+         */\r
+       public void insertListElement(String content)\r
+       {\r
+               int pos = parent.getCaretPosition();\r
+               String source = parent.getSourcePane().getText();\r
+               boolean hit = false;\r
+               String idString;\r
+               int counter = 0;\r
+               do\r
+               {\r
+                       hit = false;\r
+                       idString = "diesisteineidzumsuchenimsource" + counter;\r
+                       if(source.indexOf(idString) > -1)\r
+                       {\r
+                               counter++;\r
+                               hit = true;\r
+                               if(counter > 10000)\r
+                               {\r
+                                       return;\r
+                               }\r
+                       }\r
+               } while(hit);\r
+               Element element = getListItemParent();\r
+               if(element == null)\r
+               {\r
+                       return;\r
+               }\r
+               SimpleAttributeSet sa = new SimpleAttributeSet(element.getAttributes());\r
+               sa.addAttribute("id", idString);\r
+               parent.getExtendedHtmlDoc().replaceAttributes(element, sa, HTML.Tag.LI);\r
+               parent.refreshOnUpdate();\r
+               source = parent.getSourcePane().getText();\r
+               StringBuffer newHtmlString = new StringBuffer();\r
+               int[] positions = getPositions(element, source, true, idString);\r
+               newHtmlString.append(source.substring(0, positions[3]));\r
+               newHtmlString.append("<li>");\r
+               newHtmlString.append(content);\r
+               newHtmlString.append("</li>");\r
+               newHtmlString.append(source.substring(positions[3] + 1, source.length()));\r
+               parent.getTextPane().setText(newHtmlString.toString());\r
+               parent.refreshOnUpdate();\r
+               parent.setCaretPosition(pos - 1);\r
+               element = getListItemParent();\r
+               sa = new SimpleAttributeSet(element.getAttributes());\r
+               sa = removeAttributeByKey(sa, "id");\r
+               parent.getExtendedHtmlDoc().replaceAttributes(element, sa, HTML.Tag.LI);\r
+       }\r
+\r
+       /** Diese Methode löscht durch Stringmanipulation in jtpSource das übergebene Element,\r
+         * Alternative für removeElement in ExtendedHTMLDocument, mit closingTag wird angegeben\r
+         * ob es ein schließenden Tag gibt\r
+         */\r
+       public void removeTag(Element element, boolean closingTag)\r
+       {\r
+               if(element == null)\r
+               {\r
+                       return;\r
+               }\r
+               int pos = parent.getCaretPosition();\r
+               HTML.Tag tag = getHTMLTag(element);\r
+               // Versieht den Tag mit einer einmaligen ID\r
+               String source = parent.getSourcePane().getText();\r
+               boolean hit = false;\r
+               String idString;\r
+               int counter = 0;\r
+               do\r
+               {\r
+                       hit = false;\r
+                       idString = "diesisteineidzumsuchenimsource" + counter;\r
+                       if(source.indexOf(idString) > -1)\r
+                       {\r
+                               counter++;\r
+                               hit = true;\r
+                               if(counter > 10000)\r
+                               {\r
+                                       return;\r
+                               }\r
+                       }\r
+               } while(hit);\r
+               SimpleAttributeSet sa = new SimpleAttributeSet(element.getAttributes());\r
+               sa.addAttribute("id", idString);\r
+               parent.getExtendedHtmlDoc().replaceAttributes(element, sa, tag);\r
+               parent.refreshOnUpdate();\r
+               source = parent.getSourcePane().getText();\r
+               StringBuffer newHtmlString = new StringBuffer();\r
+               int[] position = getPositions(element, source, closingTag, idString);\r
+               if(position == null)\r
+               {\r
+                       return;\r
+               }\r
+               for(int i = 0; i < position.length; i++)\r
+               {\r
+                       if(position[i] < 0)\r
+                       {\r
+                               return;\r
+                       }\r
+               }\r
+               int beginStartTag = position[0];\r
+               int endStartTag = position[1];\r
+               if(closingTag)\r
+               {\r
+                       int beginEndTag = position[2];\r
+                       int endEndTag = position[3];\r
+                       newHtmlString.append(source.substring(0, beginStartTag));\r
+                       newHtmlString.append(source.substring(endStartTag, beginEndTag));\r
+                       newHtmlString.append(source.substring(endEndTag, source.length()));\r
+               }\r
+               else\r
+               {\r
+                       newHtmlString.append(source.substring(0, beginStartTag));\r
+                       newHtmlString.append(source.substring(endStartTag, source.length()));\r
+               }\r
+               parent.getTextPane().setText(newHtmlString.toString());\r
+               parent.refreshOnUpdate();\r
+       }\r
+\r
+       /** Diese Methode gibt jeweils den Start- und Endoffset des Elements\r
+         * sowie dem entsprechenden schließenden Tag zurück\r
+         */\r
+       private int[] getPositions(Element element, String source, boolean closingTag, String idString)\r
+       {\r
+               HTML.Tag tag = getHTMLTag(element);\r
+               int[] position = new int[4];\r
+               for(int i = 0; i < position.length; i++)\r
+               {\r
+                       position[i] = -1;\r
+               }\r
+               String searchString = "<" + tag.toString();\r
+               int caret = -1; // aktuelle Position im sourceString\r
+               if((caret = source.indexOf(idString)) != -1)\r
+               {\r
+                       position[0] = source.lastIndexOf("<",caret);\r
+                       position[1] = source.indexOf(">",caret)+1;\r
+               }\r
+               if(closingTag)\r
+               {\r
+                       String searchEndTagString = "</" + tag.toString() + ">";\r
+                       int hitUp = 0;\r
+                       int beginEndTag = -1;\r
+                       int endEndTag = -1;\r
+                       caret = position[1];\r
+                       boolean end = false;\r
+                       // Position des 1. Treffer auf den End-Tag wird bestimmt\r
+                       beginEndTag = source.indexOf(searchEndTagString, caret);\r
+                       endEndTag = beginEndTag + searchEndTagString.length();\r
+                       // Schleife läuft solange, bis keine neuen StartTags mehr gefunden werden\r
+                       int interncaret = position[1];\r
+                       do\r
+                       {\r
+                               int temphitpoint = -1;\r
+                               boolean flaghitup = false;\r
+                               // Schleife sucht zwischen dem Start- und End-Tag nach neuen Start-Tags\r
+                               hitUp = 0;\r
+                               do\r
+                               {\r
+                                       flaghitup = false;\r
+                                       temphitpoint = source.indexOf(searchString, interncaret);\r
+                                       if(temphitpoint > 0 && temphitpoint < beginEndTag)\r
+                                       {\r
+                                               hitUp++;\r
+                                               flaghitup = true;\r
+                                               interncaret = temphitpoint + searchString.length();\r
+                                       }\r
+                               } while(flaghitup);\r
+                               // hitUp enthält die Anzahl der neuen Start-Tags\r
+                               if(hitUp == 0)\r
+                               {\r
+                                       end = true;\r
+                               }\r
+                               else\r
+                               {\r
+                                       for(int i = 1; i <= hitUp; i++)\r
+                                       {\r
+                                               caret = endEndTag;\r
+                                               beginEndTag = source.indexOf(searchEndTagString, caret);\r
+                                               endEndTag = beginEndTag + searchEndTagString.length();\r
+                                       }\r
+                                       end = false;\r
+                               }\r
+                       } while(!end);\r
+                       if(beginEndTag < 0 | endEndTag < 0)\r
+                       {\r
+                               return null;\r
+                       }\r
+                       position[2] = beginEndTag;\r
+                       position[3] = endEndTag;\r
+               }\r
+               return position;\r
+       }\r
+\r
+       /* Diese Methode prüft ob der übergebene Tag sich in der Hierachie nach oben befindet */\r
+       public boolean checkParentsTag(HTML.Tag tag)\r
+       {\r
+               Element e = parent.getExtendedHtmlDoc().getParagraphElement(parent.getCaretPosition());\r
+               String tagString = tag.toString();\r
+               if(e.getName().equalsIgnoreCase(tag.toString()))\r
+               {\r
+                       return true;\r
+               }\r
+               do\r
+               {\r
+                       if((e = e.getParentElement()).getName().equalsIgnoreCase(tagString))\r
+                       {\r
+                               return true;\r
+                       }\r
+               } while(!(e.getName().equalsIgnoreCase("html")));\r
+               return false;\r
+       }\r
+\r
+       /* Diese Methoden geben das erste gefundende dem übergebenen tags entsprechende Element zurück */\r
+       public Element getListItemParent()\r
+       {\r
+               String listItemTag = HTML.Tag.LI.toString();\r
+               Element eleSearch = parent.getExtendedHtmlDoc().getCharacterElement(parent.getCaretPosition());\r
+               do\r
+               {\r
+                       if(listItemTag.equals(eleSearch.getName()))\r
+                       {\r
+                               return eleSearch;\r
+                       }\r
+                       eleSearch = eleSearch.getParentElement();\r
+               } while(eleSearch.getName() != HTML.Tag.HTML.toString());\r
+               return null;\r
+       }\r
+\r
+       /* Diese Methoden entfernen Attribute aus dem SimpleAttributeSet, gemäß den übergebenen Werten, und\r
+               geben das Ergebnis als SimpleAttributeSet zurück*/\r
+       public SimpleAttributeSet removeAttributeByKey(SimpleAttributeSet sourceAS, String removeKey)\r
+       {\r
+               SimpleAttributeSet temp = new SimpleAttributeSet();\r
+               temp.addAttribute(removeKey, "NULL");\r
+               return removeAttribute(sourceAS, temp);\r
+       }\r
+\r
+       public SimpleAttributeSet removeAttribute(SimpleAttributeSet sourceAS, SimpleAttributeSet removeAS)\r
+       {\r
+               try\r
+               {\r
+                       String[] sourceKeys = new String[sourceAS.getAttributeCount()];\r
+                       String[] sourceValues = new String[sourceAS.getAttributeCount()];\r
+                       Enumeration sourceEn = sourceAS.getAttributeNames();\r
+                       int i = 0;\r
+                       while(sourceEn.hasMoreElements())\r
+                       {\r
+                               Object temp = new Object();\r
+                               temp = sourceEn.nextElement();\r
+                               sourceKeys[i] = (String) temp.toString();\r
+                               sourceValues[i] = new String();\r
+                               sourceValues[i] = (String) sourceAS.getAttribute(temp).toString();\r
+                               i++;\r
+                       }\r
+                       String[] removeKeys = new String[removeAS.getAttributeCount()];\r
+                       String[] removeValues = new String[removeAS.getAttributeCount()];\r
+                       Enumeration removeEn = removeAS.getAttributeNames();\r
+                       int j = 0;\r
+                       while(removeEn.hasMoreElements())\r
+                       {\r
+                               removeKeys[j] = (String) removeEn.nextElement().toString();\r
+                               removeValues[j] = (String) removeAS.getAttribute(removeKeys[j]).toString();\r
+                               j++;\r
+                       }\r
+                       SimpleAttributeSet result = new SimpleAttributeSet();\r
+                       boolean hit = false;\r
+                       for(int countSource = 0; countSource < sourceKeys.length; countSource++)\r
+                       {\r
+                               hit = false;\r
+                               if(sourceKeys[countSource] == "name" | sourceKeys[countSource] == "resolver")\r
+                               {\r
+                                       hit = true;\r
+                               }\r
+                               else\r
+                               {\r
+                                       for(int countRemove = 0; countRemove < removeKeys.length; countRemove++)\r
+                                       {\r
+                                               if(removeKeys[countRemove] != "NULL")\r
+                                               {\r
+                                                       if(sourceKeys[countSource].toString() == removeKeys[countRemove].toString())\r
+                                                       {\r
+                                                               if(removeValues[countRemove] != "NULL")\r
+                                                               {\r
+                                                                       if(sourceValues[countSource].toString() == removeValues[countRemove].toString())\r
+                                                                       {\r
+                                                                               hit = true;\r
+                                                                       }\r
+                                                               }\r
+                                                               else if(removeValues[countRemove] == "NULL")\r
+                                                               {\r
+                                                                       hit = true;\r
+                                                               }\r
+                                                       }\r
+                                               }\r
+                                               else if(removeKeys[countRemove] == "NULL")\r
+                                               {\r
+                                                       if(sourceValues[countSource].toString() == removeValues[countRemove].toString())\r
+                                                       {\r
+                                                               hit = true;\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                               }\r
+                               if(!hit)\r
+                               {\r
+                                       result.addAttribute(sourceKeys[countSource].toString(), sourceValues[countSource].toString());\r
+                               }\r
+                       }\r
+                       return result;\r
+               }\r
+               catch (ClassCastException cce)\r
+               {\r
+                       return null;\r
+               }\r
+       }\r
+\r
+       /* liefert den entsprechenden HTML.Tag zum Element zurück */\r
+       public HTML.Tag getHTMLTag(Element e)\r
+       {\r
+               if(tags.containsKey(e.getName()))\r
+               {\r
+                       return (HTML.Tag)tags.get(e.getName());\r
+               }\r
+               else\r
+               {\r
+                       return null;\r
+               }\r
+       }\r
+\r
+       public String[] getUniString(int strings)\r
+       {\r
+               parent.refreshOnUpdate();\r
+               String[] result = new String[strings];\r
+               String source = parent.getSourcePane().getText();\r
+               for(int i=0; i<strings; i++)\r
+               {\r
+                       int start = -1, end = -1;\r
+                       boolean hit = false;\r
+                       String idString;\r
+                       int counter = 0;\r
+                       do\r
+                       {\r
+                               hit = false;\r
+                               idString = "diesisteineidzumsuchen" + counter + "#" + i;\r
+                               if(source.indexOf(idString) > -1)\r
+                               {\r
+                                       counter++;\r
+                                       hit = true;\r
+                                       if(counter > 10000)\r
+                                       {\r
+                                               return null;\r
+                                       }\r
+                               }\r
+                       } while(hit);\r
+                       result[i] = idString;\r
+               }\r
+               return result;\r
+       }\r
+\r
+       public void delete()\r
+       throws BadLocationException,IOException\r
+       {\r
+               JTextPane jtpMain = parent.getTextPane();\r
+               JTextPane jtpSource = parent.getSourcePane();\r
+               ExtendedHTMLDocument htmlDoc = parent.getExtendedHtmlDoc();\r
+               int selStart = jtpMain.getSelectionStart();\r
+               int selEnd = jtpMain.getSelectionEnd();\r
+               String[] posStrings = getUniString(2);\r
+               if(posStrings == null)\r
+               {\r
+                       return;\r
+               }\r
+               htmlDoc.insertString(selStart,posStrings[0],null);\r
+               htmlDoc.insertString(selEnd+posStrings[0].length(),posStrings[1],null);\r
+               parent.refreshOnUpdate();\r
+               int start = jtpSource.getText().indexOf(posStrings[0]);\r
+               int end = jtpSource.getText().indexOf(posStrings[1]);\r
+               if(start == -1 || end == -1)\r
+               {\r
+                       return;\r
+               }\r
+               String htmlString = new String();\r
+               htmlString += jtpSource.getText().substring(0,start);\r
+               htmlString += jtpSource.getText().substring(start + posStrings[0].length(), end);\r
+               htmlString += jtpSource.getText().substring(end + posStrings[1].length(), jtpSource.getText().length());\r
+               String source = htmlString;\r
+               end = end - posStrings[0].length();\r
+               htmlString = new String();\r
+               htmlString += source.substring(0,start);\r
+               htmlString += getAllTableTags(source.substring(start, end));\r
+               htmlString += source.substring(end, source.length());\r
+               parent.getTextPane().setText(htmlString);\r
+               parent.refreshOnUpdate();\r
+       }\r
+\r
+       private String getAllTableTags(String source)\r
+       throws BadLocationException,IOException\r
+       {\r
+               StringBuffer result = new StringBuffer();\r
+               int caret = -1;\r
+               do\r
+               {\r
+                       caret++;\r
+                       int[] tableCarets = new int[6];\r
+                       tableCarets[0] = source.indexOf("<table",caret);\r
+                       tableCarets[1] = source.indexOf("<tr",caret);\r
+                       tableCarets[2] = source.indexOf("<td",caret);\r
+                       tableCarets[3] = source.indexOf("</table",caret);\r
+                       tableCarets[4] = source.indexOf("</tr",caret);\r
+                       tableCarets[5] = source.indexOf("</td",caret);\r
+                       java.util.Arrays.sort(tableCarets);\r
+                       caret = -1;\r
+                       for(int i=0; i<tableCarets.length; i++)\r
+                       {\r
+                               if(tableCarets[i] >= 0)\r
+                               {\r
+                                       caret = tableCarets[i];\r
+                                       break;\r
+                               }\r
+                       }\r
+                       if(caret != -1)\r
+                       {\r
+                               result.append(source.substring(caret,source.indexOf(">",caret)+1));\r
+                       }\r
+               } while(caret != -1);\r
+               return result.toString();\r
+       }\r
+\r
+}
\ No newline at end of file
diff --git a/ekit/com/hexidec/ekit/component/ImageDialog.java b/ekit/com/hexidec/ekit/component/ImageDialog.java
new file mode 100644 (file)
index 0000000..7744bf7
--- /dev/null
@@ -0,0 +1,388 @@
+package com.hexidec.ekit.component;\r
+\r
+import com.hexidec.ekit.EkitCore;\r
+import java.awt.Insets;\r
+import java.awt.Container;\r
+import java.awt.Cursor;\r
+import java.awt.Dimension;\r
+import java.awt.event.ActionListener;\r
+import java.awt.FlowLayout;\r
+import javax.swing.border.*;\r
+import javax.swing.BorderFactory;\r
+import javax.swing.Box;\r
+import javax.swing.BoxLayout;\r
+import javax.swing.event.ListSelectionListener;\r
+import javax.swing.event.ListSelectionEvent;\r
+import javax.swing.JButton;\r
+import javax.swing.JDialog;\r
+import javax.swing.JEditorPane;\r
+import javax.swing.JLabel;\r
+import javax.swing.JList;\r
+import javax.swing.JPanel;\r
+import javax.swing.JScrollPane;\r
+import javax.swing.JTextField;\r
+import javax.swing.JTextPane;\r
+import javax.swing.ListSelectionModel;\r
+import javax.swing.SwingConstants;\r
+import javax.swing.text.html.HTML;\r
+import javax.swing.text.html.HTMLDocument;\r
+import javax.swing.text.html.HTMLEditorKit;\r
+import javax.swing.WindowConstants;\r
+\r
+public class ImageDialog extends JDialog implements ActionListener\r
+{\r
+       private final String[]Borders = new String[] { "none", "solid", "dotted", "dashed", "double", "groove",\r
+                                                                    "ridge", "inset", "outset" };\r
+       private String[]BorderColors = new String[]  { "aqua", "black", "blue", "fuschia", "gray",\r
+                                                                    "green", "lime", "maroon", "navy", "olive",\r
+                                                                    "purple", "red", "silver", "teal", "white", "yellow" };\r
+       private String[]BorderSizes = new String[]   { "none", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" };\r
+       private final String[]Wraps = new String[]   { "none", "left", "right", "top", "middle", "bottom" };\r
+       private EkitCore ParentEkit;\r
+       private ExtendedHTMLEditorKit ImageHtmlKit;\r
+       private HTMLDocument ImageHtmlDoc;\r
+       private JList WrapList;\r
+       private JList BorderList;\r
+       private JList BorderSizeList;\r
+       private JList BorderColorList;\r
+       private JList ImageList;\r
+       private JTextField ImageAltText;\r
+       private JTextField ImageWidth;\r
+       private JTextField ImageHeight;\r
+       private JEditorPane PreviewPane;\r
+       private String ImageDir;\r
+       private String[]Images;\r
+       private String PreviewImage;\r
+       private String SelectedImage;\r
+\r
+       public ImageDialog(EkitCore parentEkit, String imageDir, String[] imageList, String title, boolean modal)\r
+       {\r
+               super(parentEkit.getFrame(), title, modal);\r
+               ImageDir = imageDir;\r
+               Images = imageList;\r
+               ParentEkit = parentEkit;\r
+               SelectedImage = null;\r
+               init();\r
+       }\r
+\r
+       public void actionPerformed(java.awt.event.ActionEvent e)\r
+       {\r
+               if(e.getActionCommand().equals("apply"))\r
+               {\r
+                       ListSelectionModel sm = ImageList.getSelectionModel();\r
+                       if(sm.isSelectionEmpty())\r
+                       {\r
+                               SimpleInfoDialog sidAbout = new SimpleInfoDialog(ParentEkit.getFrame(), "Error", true, "No image selected", SimpleInfoDialog.ERROR);\r
+                               ImageList.requestFocus();\r
+                       }\r
+                       else\r
+                       {\r
+                               if(validateControls())\r
+                               {\r
+                                       previewSelectedImage();\r
+                               }\r
+                       }\r
+               }       \r
+               if(e.getActionCommand().equals("save"))\r
+               {\r
+                       ListSelectionModel sm = ImageList.getSelectionModel();\r
+                       if(sm.isSelectionEmpty())\r
+                       {\r
+                               SimpleInfoDialog sidAbout = new SimpleInfoDialog(ParentEkit.getFrame(), "Error", true, "No image selected", SimpleInfoDialog.ERROR);\r
+                               ImageList.requestFocus();\r
+                       }\r
+                       else\r
+                       {\r
+                               if(validateControls())\r
+                               {\r
+                                       previewSelectedImage();\r
+                                       SelectedImage = PreviewImage;\r
+                                       hide();\r
+                               }\r
+                       }\r
+               }\r
+               else if(e.getActionCommand().equals("cancel"))\r
+               {\r
+                       hide();\r
+               }\r
+       }\r
+\r
+       public void init()\r
+       {\r
+               SelectedImage="";\r
+               Container contentPane = getContentPane();\r
+               contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS));\r
+               //setBounds(100,100,500,300);\r
+               setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE);\r
+\r
+               ImageList = new JList(Images);\r
+               ImageList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);\r
+               ImageList.clearSelection();\r
+            ListSelectionModel lsm = ImageList.getSelectionModel();\r
+\r
+               /* Create the editor kit, document, and stylesheet */\r
+               PreviewPane = new JEditorPane();\r
+               PreviewPane.setEditable(false);\r
+               ImageHtmlKit = new ExtendedHTMLEditorKit();\r
+               ImageHtmlDoc = (HTMLDocument)(ImageHtmlKit.createDefaultDocument());\r
+               ImageHtmlKit.setDefaultCursor(new Cursor(Cursor.TEXT_CURSOR));\r
+               PreviewPane.setCaretPosition(0);\r
+               //PreviewPane.getDocument().addDocumentListener(this);\r
+               //StyleSheet styleSheet = ImageHtmlDoc.getStyleSheet();\r
+               //ImageStyleSheet = styleSheet;\r
+               lsm.addListSelectionListener(new ListSelectionListener() \r
+               {\r
+                       public void valueChanged(ListSelectionEvent e)\r
+                       {\r
+                               if(!e.getValueIsAdjusting() && validateControls())\r
+                               {\r
+                                       previewSelectedImage();\r
+                               }\r
+                       }\r
+                               \r
+               });\r
+\r
+               JScrollPane imageScrollPane = new JScrollPane(ImageList);\r
+               imageScrollPane.setPreferredSize(new Dimension(200,250));\r
+               imageScrollPane.setMaximumSize(new Dimension(200,250));\r
+               imageScrollPane.setAlignmentX(LEFT_ALIGNMENT);\r
+               JPanel centerPanel = new JPanel();\r
+               centerPanel.setLayout(new BoxLayout(centerPanel, BoxLayout.X_AXIS));\r
+               centerPanel.add(imageScrollPane);\r
+               centerPanel.setBorder(BorderFactory.createTitledBorder("Server Images"));\r
+\r
+               /* Set up the text pane */\r
+               PreviewPane.setEditorKit(ImageHtmlKit);\r
+               PreviewPane.setDocument(ImageHtmlDoc);\r
+               PreviewPane.setMargin(new Insets(4, 4, 4, 4));\r
+               JScrollPane previewViewport = new JScrollPane(PreviewPane);\r
+               previewViewport.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);\r
+               previewViewport.setPreferredSize(new Dimension(250,250));\r
+               centerPanel.add(previewViewport); \r
+\r
+               JPanel controlsPanel = new JPanel();\r
+               controlsPanel.setLayout(new BoxLayout(controlsPanel, BoxLayout.Y_AXIS));\r
+               JPanel altPanel = new JPanel();\r
+               altPanel.setLayout(new BoxLayout(altPanel, BoxLayout.X_AXIS));\r
+               altPanel.add(Box.createHorizontalStrut(10));\r
+               JLabel imageAltTextLabel = new JLabel("Alternate Text:", SwingConstants.LEFT);    \r
+               altPanel.add(imageAltTextLabel);\r
+\r
+               ImageAltText = new JTextField("");\r
+               ImageAltText.addActionListener(this);\r
+               ImageAltText.setPreferredSize(new Dimension(300,25));\r
+               ImageAltText.setMaximumSize(new Dimension(600,25));\r
+               altPanel.add(ImageAltText);\r
+               altPanel.add(Box.createHorizontalStrut(10));\r
+               controlsPanel.add(altPanel);\r
+\r
+               controlsPanel.add(Box.createVerticalStrut(5));\r
+\r
+               JPanel dimPanel = new JPanel();\r
+               dimPanel.setLayout(new BoxLayout(dimPanel, BoxLayout.X_AXIS));\r
+               dimPanel.add(Box.createHorizontalStrut(10));\r
+               JLabel imageWidthLabel = new JLabel("Width:", SwingConstants.LEFT);       \r
+               dimPanel.add(imageWidthLabel);\r
+               ImageWidth = new JTextField("");\r
+               ImageWidth.setPreferredSize(new Dimension(40,25));\r
+               ImageWidth.setMaximumSize(new Dimension(40,25));\r
+               dimPanel.add(ImageWidth);\r
+               JLabel imageWidthPixels = new JLabel("pix", SwingConstants.LEFT);         \r
+               imageWidthPixels.setPreferredSize(new Dimension(20,10));\r
+               dimPanel.add(imageWidthPixels);\r
+               dimPanel.add(Box.createHorizontalStrut(10));\r
+               JLabel imageHeightLabel = new JLabel("Height:", SwingConstants.LEFT);     \r
+               dimPanel.add(imageHeightLabel);\r
+               ImageHeight = new JTextField("");\r
+               ImageHeight.setPreferredSize(new Dimension(40,25));\r
+               ImageHeight.setMaximumSize(new Dimension(40,25));\r
+               dimPanel.add(ImageHeight);\r
+               JLabel imageHeightPixels = new JLabel("pix", SwingConstants.LEFT);        \r
+               imageHeightPixels.setPreferredSize(new Dimension(20,10));\r
+               dimPanel.add(imageHeightPixels);\r
+               dimPanel.add(Box.createHorizontalStrut(10));\r
+\r
+               JLabel wrapLabel = new JLabel("Wrap:", SwingConstants.LEFT);\r
+               dimPanel.add(wrapLabel);\r
+               WrapList = new JList(Wraps);\r
+               WrapList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);\r
+               WrapList.getSelectionModel().setSelectionInterval(0,0);\r
+               JScrollPane wrapScrollPane = new JScrollPane(WrapList);\r
+               wrapScrollPane.setAlignmentX(LEFT_ALIGNMENT);\r
+               wrapScrollPane.setPreferredSize(new Dimension(80,40));\r
+               wrapScrollPane.setMaximumSize(new Dimension(80,100));\r
+               dimPanel.add(wrapScrollPane);\r
+               controlsPanel.add(dimPanel);\r
+\r
+               //JPanel borderPanel = new JPanel();\r
+               //JLabel borderStyleLabel = new JLabel("Style:", SwingConstants.LEFT);\r
+               //borderPanel.add(borderStyleLabel);\r
+               //BorderList = new JList(Borders);\r
+               //BorderList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);\r
+               //BorderList.getSelectionModel().setSelectionInterval(0,0);\r
+               //JScrollPane borderScrollPane = new JScrollPane(BorderList);\r
+               //borderScrollPane.setAlignmentX(LEFT_ALIGNMENT);\r
+               //borderScrollPane.setPreferredSize(new Dimension(80,40));\r
+               //borderScrollPane.setMaximumSize(new Dimension(80,100));\r
+               //borderPanel.add(borderScrollPane);\r
+               //borderPanel.add(Box.createHorizontalStrut(5));\r
+\r
+               dimPanel.add(Box.createHorizontalStrut(5));\r
+               JLabel borderSizeLabel = new JLabel("Border Size:", SwingConstants.LEFT);\r
+               dimPanel.add(borderSizeLabel);\r
+               BorderSizeList = new JList(BorderSizes);\r
+               BorderSizeList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);\r
+               BorderSizeList.getSelectionModel().setSelectionInterval(0,0);\r
+               JScrollPane borderSizeScrollPane = new JScrollPane(BorderSizeList);\r
+               borderSizeScrollPane.setAlignmentX(LEFT_ALIGNMENT);\r
+               borderSizeScrollPane.setPreferredSize(new Dimension(80,40));\r
+               borderSizeScrollPane.setMaximumSize(new Dimension(80,100));\r
+               dimPanel.add(borderSizeScrollPane);\r
+               dimPanel.add(Box.createHorizontalStrut(10));\r
+               dimPanel.add(Box.createVerticalStrut(10));\r
+\r
+               //JLabel borderColorLabel = new JLabel("Color:", SwingConstants.LEFT);\r
+               //borderPanel.add(borderColorLabel);\r
+               //BorderColorList = new JList(BorderColors);\r
+               //BorderColorList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);\r
+               //JScrollPane borderColorScrollPane = new JScrollPane(BorderColorList);\r
+               //borderColorScrollPane.setAlignmentX(LEFT_ALIGNMENT);\r
+               //borderColorScrollPane.setPreferredSize(new Dimension(80,40));\r
+               //borderPanel.add(borderColorScrollPane);\r
+               //controlsPanel.add(borderPanel);\r
+\r
+               JPanel buttonPanel= new JPanel();\r
+               buttonPanel.setBorder(new SoftBevelBorder(BevelBorder.LOWERED));\r
+               JButton applyButton = new JButton("Apply");\r
+               applyButton.setActionCommand("apply");\r
+               applyButton.addActionListener(this);\r
+\r
+               JButton saveButton = new JButton("Accept");\r
+               saveButton.setActionCommand("save");\r
+               saveButton.addActionListener(this);\r
+               JButton cancelButton = new JButton("Cancel");\r
+               cancelButton.setActionCommand("cancel");\r
+               cancelButton.addActionListener(this);\r
+\r
+               buttonPanel.add(applyButton);\r
+               buttonPanel.add(saveButton);\r
+               buttonPanel.add(cancelButton);\r
+\r
+               contentPane.add(centerPanel);\r
+               contentPane.add(controlsPanel);\r
+               contentPane.add(buttonPanel);\r
+               this.pack();\r
+               setVisible(true);\r
+    }\r
+\r
+    private void previewSelectedImage()\r
+    {\r
+         ListSelectionModel sm = ImageList.getSelectionModel();\r
+         if(!sm.isSelectionEmpty())\r
+         {\r
+               String theImage = Images[sm.getMinSelectionIndex()];\r
+               try\r
+               {\r
+                       // Clear the preview area\r
+                       PreviewPane.setText("");\r
+                       StringBuffer attrString = new StringBuffer();\r
+                       if(!ImageHeight.getText().equals(""))\r
+                       {\r
+                               attrString.append("HEIGHT=\"" + ImageHeight.getText() + "\" ");\r
+                       }\r
+                       if(!ImageWidth.getText().equals(""))\r
+                       {\r
+                               attrString.append("WIDTH=\"" + ImageWidth.getText() + "\" ");\r
+                       }\r
+                       if(!ImageAltText.getText().equals(""))\r
+                       {\r
+                               attrString.append("ALT=\"" + ImageAltText.getText() + "\" ");\r
+                       }\r
+                       if(!WrapList.getSelectionModel().isSelectionEmpty())\r
+                       {\r
+                               String theWrap = Wraps[WrapList.getSelectionModel().getMinSelectionIndex()];\r
+                               if(!theWrap.equals("none"))\r
+                               {\r
+                                       attrString.append("ALIGN=\"" + theWrap + "\" ");\r
+                               }\r
+                       }\r
+                       //if(!BorderList.getSelectionModel().isSelectionEmpty())\r
+                       //{\r
+                               //String theBorder = Borders[BorderList.getSelectionModel().getMinSelectionIndex()];\r
+                               //if(!theBorder.equals("none"))\r
+                               //{\r
+                                       String borderSize = null;\r
+                                       String borderColor = null;\r
+                                       if(!BorderSizeList.getSelectionModel().isSelectionEmpty())\r
+                                       {\r
+                                               borderSize = BorderSizes[BorderSizeList.getSelectionModel().getMinSelectionIndex()];\r
+                                               if(!borderSize.equals("none"))\r
+                                                       attrString.append("BORDER=" + borderSize);\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               borderSize = BorderSizes[0];\r
+                                       }\r
+                                       //if(!BorderColorList.getSelectionModel().isSelectionEmpty())\r
+                                       //{\r
+                                       //      borderColor = BorderColors[BorderColorList.getSelectionModel().getMinSelectionIndex()];                                         \r
+                                       //}\r
+                                       //else\r
+                                       //{\r
+                                       //      borderColor = "gray";\r
+                                       //}\r
+                                       //attrString.append("STYLE=\"border: " + borderColor + " "  + borderSize + "px " + theBorder + "\"");\r
+                               //}\r
+                       //}\r
+\r
+                       \r
+                       PreviewImage = "<IMG SRC=" + ImageDir + "/" + theImage + " " + attrString.toString() + ">";\r
+                       ImageHtmlKit.insertHTML(ImageHtmlDoc, 0, PreviewImage, 0, 0, HTML.Tag.IMG);\r
+                       repaint();\r
+               }\r
+               catch(Exception ex)\r
+               {\r
+                       System.err.println("Exception previewing image");\r
+               }\r
+        }\r
+    }\r
+\r
+    private boolean validateControls()\r
+    {\r
+         boolean result = true;\r
+\r
+         if(!ImageWidth.getText().equals(""))\r
+         {\r
+               try\r
+               {\r
+                       Integer.parseInt(ImageWidth.getText());\r
+               }\r
+               catch (NumberFormatException e)\r
+               {\r
+                       result = false;\r
+                       SimpleInfoDialog sidAbout = new SimpleInfoDialog(ParentEkit.getFrame(), "Error", true, "Image Width is not an integer", SimpleInfoDialog.ERROR);\r
+                       ImageWidth.requestFocus();\r
+               }\r
+         }\r
+         if( result && !ImageHeight.getText().equals(""))\r
+         {\r
+               try\r
+               {\r
+                       Integer.parseInt(ImageHeight.getText());\r
+               }\r
+               catch (NumberFormatException e)\r
+               {\r
+                       result = false;\r
+                       SimpleInfoDialog sidAbout = new SimpleInfoDialog(ParentEkit.getFrame(), "Error", true, "Image Height is not an integer", SimpleInfoDialog.ERROR);\r
+                       ImageHeight.requestFocus();\r
+               }\r
+         }\r
+\r
+        return result;\r
+    }\r
+\r
+    public String getSelectedImage()\r
+    {\r
+         return SelectedImage;\r
+    }  \r
+}\r
diff --git a/ekit/com/hexidec/ekit/component/ImageFileChooser.java b/ekit/com/hexidec/ekit/component/ImageFileChooser.java
new file mode 100644 (file)
index 0000000..ad1618c
--- /dev/null
@@ -0,0 +1,54 @@
+/*\r
+GNU Lesser General Public License\r
+\r
+ImageFileChooser\r
+Copyright (C) 2000-2002  Frits Jalvingh & Howard Kistler\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+*/\r
+\r
+package com.hexidec.ekit.component;\r
+\r
+import java.io.File;\r
+import javax.swing.JFileChooser;\r
+\r
+/** Class for providing a chooser that lets the user select an image to insert\r
+  */\r
+public class ImageFileChooser extends JFileChooser\r
+{\r
+       /** Constructor that takes a default directory to start in, specified as a File\r
+         * @param File with the default path\r
+         */\r
+       public ImageFileChooser(File fileCurrentDirectory)\r
+       {\r
+               this.setCurrentDirectory(fileCurrentDirectory);\r
+               this.setAccessory(new ImageFileChooserPreview(this));\r
+   }\r
+\r
+       /** Constructor that takes a default directory to start in, specified as a String\r
+         * @param String current directory path.\r
+         */\r
+       public ImageFileChooser(String strCurrentPath)\r
+       {\r
+               this(new File(strCurrentPath));\r
+       }\r
+\r
+       /** Empty constructor\r
+         */\r
+       public ImageFileChooser()\r
+       {\r
+               this((File)null);\r
+       }\r
+}\r
diff --git a/ekit/com/hexidec/ekit/component/ImageFileChooserPreview.java b/ekit/com/hexidec/ekit/component/ImageFileChooserPreview.java
new file mode 100644 (file)
index 0000000..307aa7e
--- /dev/null
@@ -0,0 +1,126 @@
+/*\r
+GNU Lesser General Public License\r
+\r
+ImageFileChooserPreview\r
+Copyright (C) 2000-2002  Frits Jalvingh & Howard Kistler\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+*/\r
+\r
+package com.hexidec.ekit.component;\r
+\r
+import java.awt.Dimension;\r
+import java.awt.Graphics;\r
+import java.awt.Image;\r
+import java.io.File;\r
+import javax.swing.ImageIcon;\r
+import javax.swing.JComponent;\r
+import javax.swing.JFileChooser;\r
+import java.beans.PropertyChangeEvent;\r
+import java.beans.PropertyChangeListener;\r
+\r
+/** Class provides a preview window for the selected image file\r
+  */\r
+class ImageFileChooserPreview extends JComponent implements PropertyChangeListener\r
+{\r
+       private static final int previewWidth  = 100;\r
+       private static final int previewHeight = 100;\r
+\r
+       private ImageIcon imageThumb = null;\r
+       private File imageFile = null;\r
+\r
+       /** This class requires a file chooser to register with so this class will\r
+         * be notified when a new file is selected in the browser.\r
+         * @param JFileChooser that this preview window is used in.\r
+         */\r
+       public ImageFileChooserPreview(JFileChooser parent)\r
+       {\r
+               setPreferredSize(new Dimension(previewWidth , previewHeight));\r
+               parent.addPropertyChangeListener(this);\r
+       }\r
+\r
+       /** Loads a new image into the preview window, and scales it if necessary.\r
+         */\r
+       public void loadImage()\r
+       {\r
+               if(imageFile == null)\r
+               {\r
+                       imageThumb = null;\r
+                       return;\r
+               }\r
+               imageThumb = new ImageIcon(imageFile.getPath());\r
+\r
+               // Check if thumb requires scaling\r
+               if(imageThumb.getIconHeight() < previewHeight && imageThumb.getIconWidth() < previewWidth)\r
+               {\r
+                       return;\r
+               }\r
+               int     w = previewWidth;\r
+               int     h = previewHeight;\r
+               if(imageThumb.getIconHeight() > imageThumb.getIconWidth())\r
+               {\r
+                       w = -1;\r
+               }\r
+               else\r
+               {\r
+                       h = -1;\r
+               }\r
+               imageThumb = new ImageIcon(imageThumb.getImage().getScaledInstance(w, h, Image.SCALE_DEFAULT));\r
+       }\r
+\r
+       /** Callback (event handler) to indicate that a property of the\r
+         * JFileChooser has changed. If the selected file has changed cause a new\r
+         * thumbnail to load.\r
+         */\r
+       public void propertyChange(PropertyChangeEvent e)\r
+       {\r
+               if(e.getPropertyName().equals(JFileChooser.SELECTED_FILE_CHANGED_PROPERTY))\r
+               {\r
+                       imageFile = (File)e.getNewValue();\r
+                       if(isShowing())\r
+                       {\r
+                               loadImage();\r
+                               repaint();\r
+                       }\r
+               }\r
+       }\r
+\r
+       /** Paints the icon of the current image, if one's present..\r
+         * @param Graphics object to use when painting the component.\r
+         */\r
+       public void paintComponent(Graphics g)\r
+       {\r
+               if(imageThumb == null)\r
+               {\r
+                       loadImage();\r
+               }\r
+               if(imageThumb == null)\r
+               {\r
+                       return;\r
+               }\r
+               int     x = (getWidth() - imageThumb.getIconWidth()) / 2;\r
+               int     y = (getHeight() - imageThumb.getIconHeight()) / 2;\r
+               if(y < 0)\r
+               {\r
+                       y = 0;\r
+               }\r
+               if(x < 5)\r
+               {\r
+                       x = 5;\r
+               }\r
+               imageThumb.paintIcon(this, g, x, y);\r
+       }\r
+}\r
+\r
diff --git a/ekit/com/hexidec/ekit/component/JButtonNoFocus.java b/ekit/com/hexidec/ekit/component/JButtonNoFocus.java
new file mode 100644 (file)
index 0000000..79e3524
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+GNU Lesser General Public License
+
+JButtonNoFocus
+Copyright (C) 2000-2003 Howard Kistler
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+package com.hexidec.ekit.component;
+
+import javax.swing.Action;
+import javax.swing.Icon;
+import javax.swing.JButton;
+
+/** Class for providing a JButton that does not obtain focus
+  */
+public class JButtonNoFocus extends JButton
+{
+       public JButtonNoFocus()                       { super();           this.setRequestFocusEnabled(false); }
+       public JButtonNoFocus(Action a)               { super(a);          this.setRequestFocusEnabled(false); }
+       public JButtonNoFocus(Icon icon)              { super(icon);       this.setRequestFocusEnabled(false); }
+       public JButtonNoFocus(String text)            { super(text);       this.setRequestFocusEnabled(false); }
+       public JButtonNoFocus(String text, Icon icon) { super(text, icon); this.setRequestFocusEnabled(false); }
+
+       public boolean isFocusable()
+       {
+               return false;
+       }
+
+       // deprecated in 1.4 with isFocusable(), left in for 1.3 compatibility
+       public boolean isFocusTraversable()
+       {
+               return false;
+       }
+}
diff --git a/ekit/com/hexidec/ekit/component/JComboBoxNoFocus.java b/ekit/com/hexidec/ekit/component/JComboBoxNoFocus.java
new file mode 100644 (file)
index 0000000..2b38567
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+GNU Lesser General Public License
+
+JComboBoxNoFocus
+Copyright (C) 2000-2003 Howard Kistler
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+package com.hexidec.ekit.component;
+
+import javax.swing.JComboBox;
+
+/** Class for providing a JComboBox that does not obtain focus
+  */
+public class JComboBoxNoFocus extends JComboBox
+{
+       public JComboBoxNoFocus() { super();  this.setRequestFocusEnabled(false); }
+
+       public boolean isFocusable()
+       {
+               return false;
+       }
+
+       // deprecated in 1.4 with isFocusable(), left in for 1.3 compatibility
+       public boolean isFocusTraversable()
+       {
+               return false;
+       }
+}
diff --git a/ekit/com/hexidec/ekit/component/JToggleButtonNoFocus.java b/ekit/com/hexidec/ekit/component/JToggleButtonNoFocus.java
new file mode 100644 (file)
index 0000000..991c20f
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+GNU Lesser General Public License
+
+JToggleButtonNoFocus
+Copyright (C) 2000-2003 Howard Kistler
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+package com.hexidec.ekit.component;
+
+import javax.swing.Action;
+import javax.swing.Icon;
+import javax.swing.JToggleButton;
+
+/** Class for providing a JToggleButton that does not obtain focus
+  */
+public class JToggleButtonNoFocus extends JToggleButton
+{
+       public JToggleButtonNoFocus()                       { super();           this.setRequestFocusEnabled(false); }
+       public JToggleButtonNoFocus(Action a)               { super(a);          this.setRequestFocusEnabled(false); }
+       public JToggleButtonNoFocus(Icon icon)              { super(icon);       this.setRequestFocusEnabled(false); }
+       public JToggleButtonNoFocus(String text)            { super(text);       this.setRequestFocusEnabled(false); }
+       public JToggleButtonNoFocus(String text, Icon icon) { super(text, icon); this.setRequestFocusEnabled(false); }
+
+       public boolean isFocusable()
+       {
+               return false;
+       }
+
+       // deprecated in 1.4 with isFocusable(), left in for 1.3 compatibility
+       public boolean isFocusTraversable()
+       {
+               return false;
+       }
+}
diff --git a/ekit/com/hexidec/ekit/component/MutableFilter.java b/ekit/com/hexidec/ekit/component/MutableFilter.java
new file mode 100644 (file)
index 0000000..2d9d4af
--- /dev/null
@@ -0,0 +1,77 @@
+/*\r
+GNU Lesser General Public License\r
+\r
+MutableFilter\r
+Copyright (C) 2000-2003 Howard Kistler\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+*/\r
+\r
+package com.hexidec.ekit.component;\r
+\r
+import java.io.File;\r
+import javax.swing.filechooser.FileFilter;\r
+\r
+/** Class for providing JFileChooser with a FileFilter\r
+  */\r
+public class MutableFilter extends FileFilter\r
+{\r
+       private String[] acceptableExtensions;\r
+       private String descriptor;\r
+\r
+       public MutableFilter(String[] exts, String desc)\r
+       {\r
+               acceptableExtensions = exts;\r
+               StringBuffer strbDesc = new StringBuffer(desc + " (");\r
+               for(int i = 0; i < acceptableExtensions.length; i++)\r
+               {\r
+                       if(i > 0) { strbDesc.append(", "); }\r
+                       strbDesc.append("*." + acceptableExtensions[i]);\r
+               }\r
+               strbDesc.append(")");\r
+               descriptor = strbDesc.toString();\r
+       }\r
+\r
+       public boolean accept(File file)\r
+       {\r
+               if(file.isDirectory())\r
+               {\r
+                       return true;\r
+               }\r
+               String fileName = file.getName();\r
+               String fileExt = fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length()).toLowerCase();\r
+               if(fileExt != null)\r
+               {\r
+                       for(int i = 0; i < acceptableExtensions.length; i++)\r
+                       {\r
+                               if(fileExt.equals(acceptableExtensions[i]))\r
+                               {\r
+                                       return true;\r
+                               }\r
+                       }\r
+                       return false;\r
+               }\r
+               else\r
+               {\r
+                       return false;\r
+               }\r
+       }\r
+\r
+       public String getDescription()\r
+       {\r
+               return descriptor;\r
+       }\r
+}\r
+\r
diff --git a/ekit/com/hexidec/ekit/component/PropertiesDialog.java b/ekit/com/hexidec/ekit/component/PropertiesDialog.java
new file mode 100644 (file)
index 0000000..6526087
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+GNU Lesser General Public License
+
+PropertiesDialog
+Copyright (C) 2003 Howard Kistler
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+package com.hexidec.ekit.component;
+
+import java.awt.Frame;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.StringTokenizer;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JDialog;
+import javax.swing.JOptionPane;
+import javax.swing.JTextField;
+
+import com.hexidec.util.Translatrix;
+
+/** Class for providing a dialog that lets the user specify values for tag attributes
+  */
+public class PropertiesDialog extends JDialog
+{
+       private JOptionPane jOptionPane;
+       private Hashtable htInputFields;
+
+       public PropertiesDialog(Frame parent, String[] fields, String[] types, String[] values, String title, boolean bModal)
+       {
+               super(parent, title, bModal);
+               htInputFields = new Hashtable();
+               final Object[] buttonLabels = { Translatrix.getTranslationString("DialogAccept"), Translatrix.getTranslationString("DialogCancel") };
+               Object[] panelContents = new Object[(fields.length * 2)];
+               int objectCount = 0;
+               for(int iter = 0; iter < fields.length; iter++)
+               {
+                       String fieldName = fields[iter];
+                       String fieldType = types[iter];
+                       Object fieldComponent;
+                       if(fieldType.equals("text"))
+                       {
+                               fieldComponent = new JTextField(3);
+                               if(values[iter] != null && values[iter].length() > 0)
+                               {
+                                       ((JTextField)(fieldComponent)).setText(values[iter]);
+                               }
+                       }
+                       else if(fieldType.equals("bool"))
+                       {
+                               fieldComponent = new JCheckBox();
+                               if(values[iter] != null)
+                               {
+                                       ((JCheckBox)(fieldComponent)).setSelected(values[iter] == "true");
+                               }
+                       }
+                       else if(fieldType.equals("combo"))
+                       {
+                               fieldComponent = new JComboBox();
+                               if(values[iter] != null)
+                               {
+                                       StringTokenizer stParse = new StringTokenizer(values[iter], ",", false);
+                                       while(stParse.hasMoreTokens())
+                                       {
+                                               ((JComboBox)(fieldComponent)).addItem(stParse.nextToken());
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               fieldComponent = new JTextField(3);
+                       }
+                       htInputFields.put(fieldName, fieldComponent);
+                       panelContents[objectCount] = fieldName; // Translatrix.getTranslationString(fieldName);
+                       panelContents[objectCount + 1] = fieldComponent;
+                       objectCount += 2;
+               }
+               jOptionPane = new JOptionPane(panelContents, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION, null, buttonLabels, buttonLabels[0]);
+
+               setContentPane(jOptionPane);
+               setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
+
+               jOptionPane.addPropertyChangeListener(new PropertyChangeListener() {
+                       public void propertyChange(PropertyChangeEvent e)
+                       {
+                               String prop = e.getPropertyName();
+                               if(isVisible() && (e.getSource() == jOptionPane) && (prop.equals(JOptionPane.VALUE_PROPERTY) || prop.equals(JOptionPane.INPUT_VALUE_PROPERTY)))
+                               {
+                                       Object value = jOptionPane.getValue();
+                                       if(value == JOptionPane.UNINITIALIZED_VALUE)
+                                       {
+                                               return;
+                                       }
+                                       if(value.equals(buttonLabels[0]))
+                                       {
+                                               setVisible(false);
+                                       }
+                                       else
+                                       {
+                                               setVisible(false);
+                                       }
+                               }
+                       }
+               });
+               this.pack();
+       }
+
+       public PropertiesDialog(Frame parent, String[] fields, String[] types, String title, boolean bModal)
+       {
+               this(parent, fields, types, new String[fields.length], title, bModal);
+       }
+
+       public String getFieldValue(String fieldName)
+       {
+               Object dataField = htInputFields.get(fieldName);
+               if(dataField instanceof JTextField)
+               {
+                       return ((JTextField)dataField).getText();
+               }
+               else if(dataField instanceof JCheckBox)
+               {
+                       if(((JCheckBox)dataField).isSelected())
+                       {
+                               return "true";
+                       }
+                       else
+                       {
+                               return "false";
+                       }
+               }
+               else if(dataField instanceof JComboBox)
+               {
+                       return (String)(((JComboBox)dataField).getSelectedItem());
+               }
+               else
+               {
+                       return (String)null;
+               }
+       }
+
+       public String getDecisionValue()
+       {
+               return jOptionPane.getValue().toString();
+       }
+}
+
diff --git a/ekit/com/hexidec/ekit/component/RelativeImageView.java b/ekit/com/hexidec/ekit/component/RelativeImageView.java
new file mode 100644 (file)
index 0000000..95adcee
--- /dev/null
@@ -0,0 +1,943 @@
+/*\r
+GNU Lesser General Public License\r
+\r
+RelativeImageView\r
+Copyright (C) 2001-2002  Frits Jalvingh & Howard Kistler\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+*/\r
+\r
+package com.hexidec.ekit.component;\r
+\r
+import java.awt.Color;\r
+import java.awt.Component;\r
+import java.awt.Container;\r
+import java.awt.Dimension;\r
+import java.awt.Graphics;\r
+import java.awt.Image;\r
+import java.awt.Point;\r
+import java.awt.Rectangle;\r
+import java.awt.Shape;\r
+import java.awt.Toolkit;\r
+import java.awt.event.MouseEvent;\r
+import java.awt.event.MouseListener;\r
+import java.awt.event.MouseMotionListener;\r
+import java.awt.image.ImageObserver;\r
+import java.io.BufferedInputStream;\r
+import java.io.ByteArrayOutputStream;\r
+import java.io.File;\r
+import java.io.InputStream;\r
+import java.io.IOException;\r
+import java.net.MalformedURLException;\r
+import java.net.URL;\r
+import java.util.Dictionary;\r
+import javax.swing.Icon;\r
+import javax.swing.ImageIcon;\r
+import javax.swing.JEditorPane;\r
+import javax.swing.text.AbstractDocument;\r
+import javax.swing.text.AttributeSet;\r
+import javax.swing.text.BadLocationException;\r
+import javax.swing.text.Document;\r
+import javax.swing.text.Element;\r
+import javax.swing.text.JTextComponent;\r
+import javax.swing.text.MutableAttributeSet;\r
+import javax.swing.text.Position;\r
+import javax.swing.text.SimpleAttributeSet;\r
+import javax.swing.text.StyledDocument;\r
+import javax.swing.text.View;\r
+import javax.swing.text.ViewFactory;\r
+import javax.swing.text.html.HTML;\r
+import javax.swing.text.html.HTMLDocument;\r
+import javax.swing.text.html.StyleSheet;\r
+import javax.swing.event.DocumentEvent;\r
+\r
+/**\r
+  * @author <a href="mailto:jal@grimor.com">Frits Jalvingh</a>\r
+  * @version 1.0\r
+  *\r
+  * This code was modeled after an artice on\r
+  * <a href="http://www.javaworld.com/javaworld/javatips/jw-javatip109.html">\r
+  * JavaWorld</a> by Bob Kenworthy.\r
+  */\r
+\r
+public class RelativeImageView extends View implements ImageObserver, MouseListener, MouseMotionListener\r
+{\r
+       public static final String TOP       = "top";\r
+       public static final String TEXTTOP   = "texttop";\r
+       public static final String MIDDLE    = "middle";\r
+       public static final String ABSMIDDLE = "absmiddle";\r
+       public static final String CENTER    = "center";\r
+       public static final String BOTTOM    = "bottom";\r
+       public static final String IMAGE_CACHE_PROPERTY = "imageCache";\r
+\r
+       private static Icon sPendingImageIcon;\r
+       private static Icon sMissingImageIcon;\r
+       private static final String PENDING_IMAGE_SRC = "icons/ImagePendingHK.gif";\r
+       private static final String MISSING_IMAGE_SRC = "icons/ImageMissingHK.gif";\r
+       private static final int DEFAULT_WIDTH  = 32;\r
+       private static final int DEFAULT_HEIGHT = 32;\r
+       private static final int DEFAULT_BORDER = 1;\r
+\r
+       private AttributeSet attr;\r
+       private Element      fElement;\r
+       private Image        fImage;\r
+       private int          fHeight;\r
+       private int          fWidth;\r
+       private Container    fContainer;\r
+       private Rectangle    fBounds;\r
+       private Component    fComponent;\r
+       private Point        fGrowBase; // base of drag while growing image\r
+       private boolean      fGrowProportionally; // should grow be proportional?\r
+       private boolean      bLoading; // set to true while the receiver is locked, to indicate the reciever is loading the image. This is used in imageUpdate.\r
+\r
+       /** Constructor\r
+         * Creates a new view that represents an IMG element.\r
+         * @param elem the element to create a view for\r
+         */\r
+       public RelativeImageView(Element elem)\r
+       {\r
+               super(elem);\r
+               initialize(elem);\r
+               StyleSheet sheet = getStyleSheet();\r
+               attr = sheet.getViewAttributes(this);\r
+       }\r
+\r
+       private void initialize(Element elem)\r
+       {\r
+               synchronized(this)\r
+               {\r
+                       bLoading = true;\r
+                       fWidth  = 0;\r
+                       fHeight = 0;\r
+               }\r
+               int width = 0;\r
+               int height = 0;\r
+               boolean customWidth = false;\r
+               boolean customHeight = false;\r
+               try\r
+               {\r
+                       fElement = elem;\r
+                       // request image from document's cache\r
+                       AttributeSet attr = elem.getAttributes();\r
+                       if(isURL())\r
+                       {\r
+                               URL src = getSourceURL();\r
+                               if(src != null)\r
+                               {\r
+                                       Dictionary cache = (Dictionary)getDocument().getProperty(IMAGE_CACHE_PROPERTY);\r
+                                       if(cache != null)\r
+                                       {\r
+                                               fImage = (Image)cache.get(src);\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               fImage = Toolkit.getDefaultToolkit().getImage(src);\r
+                                       }\r
+                               }\r
+                       }\r
+                       else\r
+                       {\r
+                               // load image from relative path\r
+                               String src = (String)fElement.getAttributes().getAttribute(HTML.Attribute.SRC);\r
+                               src = processSrcPath(src);\r
+                               fImage = Toolkit.getDefaultToolkit().createImage(src);\r
+                               try\r
+                               {\r
+                                       waitForImage();\r
+                               }\r
+                               catch(InterruptedException ie)\r
+                               {\r
+                                       fImage = null;\r
+                                       // possibly replace with the ImageBroken icon, if that's what is happening\r
+                               }\r
+                       }\r
+\r
+                       // get height & width from params or image or defaults\r
+                       height = getIntAttr(HTML.Attribute.HEIGHT, -1);\r
+                       customHeight = (height > 0);\r
+                       if(!customHeight && fImage != null)\r
+                       {\r
+                               height = fImage.getHeight(this);\r
+                       }\r
+                       if(height <= 0)\r
+                       {\r
+                               height = DEFAULT_HEIGHT;\r
+                       }\r
+\r
+                       width = getIntAttr(HTML.Attribute.WIDTH, -1);\r
+                       customWidth = (width > 0);\r
+                       if(!customWidth && fImage != null)\r
+                       {\r
+                               width = fImage.getWidth(this);\r
+                       }\r
+                       if(width <= 0)\r
+                       {\r
+                               width = DEFAULT_WIDTH;\r
+                       }\r
+\r
+                       if(fImage != null)\r
+                       {\r
+                               if(customHeight && customWidth)\r
+                               {\r
+                                       Toolkit.getDefaultToolkit().prepareImage(fImage, height, width, this);\r
+                               }\r
+                               else\r
+                               {\r
+                                       Toolkit.getDefaultToolkit().prepareImage(fImage, -1, -1, this);\r
+                               }\r
+                       }\r
+               }\r
+               finally\r
+               {\r
+                       synchronized(this)\r
+                       {\r
+                               bLoading = false;\r
+                               if(customHeight || fHeight == 0)\r
+                               {\r
+                                       fHeight = height;\r
+                               }\r
+                               if(customWidth || fWidth == 0)\r
+                               {\r
+                                       fWidth = width;\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+\r
+       /** Determines if path is in the form of a URL\r
+         */\r
+       private boolean isURL()\r
+       {\r
+               String src = (String)fElement.getAttributes().getAttribute(HTML.Attribute.SRC);\r
+               return src.toLowerCase().startsWith("file") || src.toLowerCase().startsWith("http");\r
+       }\r
+\r
+       /** Checks to see if the absolute path is availabe thru an application\r
+         * global static variable or thru a system variable. If so, appends\r
+         * the relative path to the absolute path and returns the String.\r
+         */\r
+       private String processSrcPath(String src)\r
+       {\r
+               String val = src;\r
+               File imageFile = new File(src);\r
+               if(imageFile.isAbsolute())\r
+               {\r
+                       return src;\r
+               }\r
+               boolean found = false;\r
+               Document doc = getDocument();\r
+               if(doc != null)\r
+               {\r
+                       String pv = (String)doc.getProperty("com.hexidec.ekit.docsource");\r
+                       if(pv != null)\r
+                       {\r
+                               File f = new File(pv);\r
+                               val     = (new File(f.getParent(), imageFile.getPath().toString())).toString();\r
+                               found = true;\r
+                       }\r
+               }\r
+               if(!found)\r
+               {\r
+                       String imagePath = System.getProperty("system.image.path.key");\r
+                       if(imagePath != null)\r
+                       {\r
+                               val = (new File(imagePath, imageFile.getPath())).toString();\r
+                       }\r
+               }\r
+               return val;\r
+       }\r
+\r
+       /** Method insures that the image is loaded and not a broken reference\r
+         */\r
+       private void waitForImage()\r
+       throws InterruptedException\r
+       {\r
+               int w = fImage.getWidth(this);\r
+               int h = fImage.getHeight(this);\r
+               while (true)\r
+               {\r
+                       int flags = Toolkit.getDefaultToolkit().checkImage(fImage, w, h, this);\r
+                       if(((flags & ERROR) != 0) || ((flags & ABORT) != 0 ))\r
+                       {\r
+                               throw new InterruptedException();\r
+                       }\r
+                       else if((flags & (ALLBITS | FRAMEBITS)) != 0)\r
+                       {\r
+                               return;\r
+                       }\r
+                       Thread.sleep(10);\r
+               }\r
+       }\r
+\r
+       /** Fetches the attributes to use when rendering. This is\r
+         * implemented to multiplex the attributes specified in the\r
+         * model with a StyleSheet.\r
+         */\r
+       public AttributeSet getAttributes()\r
+       {\r
+               return attr;\r
+       }\r
+\r
+       /** Method tests whether the image within a link\r
+         */\r
+       boolean isLink()\r
+       {\r
+               AttributeSet anchorAttr = (AttributeSet)fElement.getAttributes().getAttribute(HTML.Tag.A);\r
+               if(anchorAttr != null)\r
+               {\r
+                       return anchorAttr.isDefined(HTML.Attribute.HREF);\r
+               }\r
+               return false;\r
+       }\r
+\r
+       /** Method returns the size of the border to use\r
+         */\r
+       int getBorder()\r
+       {\r
+               return getIntAttr(HTML.Attribute.BORDER, isLink() ? DEFAULT_BORDER : 0);\r
+       }\r
+\r
+       /** Method returns the amount of extra space to add along an axis\r
+               */\r
+       int getSpace(int axis)\r
+       {\r
+               return getIntAttr((axis == X_AXIS) ? HTML.Attribute.HSPACE : HTML.Attribute.VSPACE, 0);\r
+       }\r
+\r
+       /** Method returns the border's color, or null if this is not a link\r
+       */\r
+       Color getBorderColor()\r
+       {\r
+               StyledDocument doc = (StyledDocument)getDocument();\r
+               return doc.getForeground(getAttributes());\r
+       }\r
+\r
+       /** Method returns the image's vertical alignment\r
+         */\r
+       float getVerticalAlignment()\r
+       {\r
+               String align = (String)fElement.getAttributes().getAttribute(HTML.Attribute.ALIGN);\r
+               if(align != null)\r
+               {\r
+                       align = align.toLowerCase();\r
+                       if(align.equals(TOP) || align.equals(TEXTTOP))\r
+                       {\r
+                               return 0.0f;\r
+                       }\r
+                       else if(align.equals(this.CENTER) || align.equals(MIDDLE) || align.equals(ABSMIDDLE))\r
+                       {\r
+                               return 0.5f;\r
+                       }\r
+               }\r
+               return 1.0f; // default alignment is bottom\r
+       }\r
+\r
+       boolean hasPixels(ImageObserver obs)\r
+       {\r
+               return ((fImage != null) && (fImage.getHeight(obs) > 0) && (fImage.getWidth(obs) > 0));\r
+       }\r
+\r
+       /** Method returns a URL for the image source, or null if it could not be determined\r
+         */\r
+       private URL getSourceURL()\r
+       {\r
+               String src = (String)fElement.getAttributes().getAttribute(HTML.Attribute.SRC);\r
+               if(src == null)\r
+               {\r
+                       return null;\r
+               }\r
+               URL reference = ((HTMLDocument)getDocument()).getBase();\r
+               try\r
+               {\r
+                       URL u = new URL(reference,src);\r
+                       return u;\r
+               }\r
+               catch(MalformedURLException mue)\r
+               {\r
+                       return null;\r
+               }\r
+       }\r
+\r
+       /** Method looks up an integer-valued attribute (not recursive!)\r
+         */\r
+       private int getIntAttr(HTML.Attribute name, int iDefault)\r
+       {\r
+               AttributeSet attr = fElement.getAttributes();\r
+               if(attr.isDefined(name))\r
+               {\r
+                       int i;\r
+                       String val = (String)attr.getAttribute(name);\r
+                       if(val == null)\r
+                       {\r
+                               i = iDefault;\r
+                       }\r
+                       else\r
+                       {\r
+                               try\r
+                               {\r
+                                       i = Math.max(0, Integer.parseInt(val));\r
+                               }\r
+                               catch(NumberFormatException nfe)\r
+                               {\r
+                                       i = iDefault;\r
+                               }\r
+                       }\r
+                       return i;\r
+               }\r
+               else\r
+               {\r
+                       return iDefault;\r
+               }\r
+       }\r
+\r
+       /**\r
+       * Establishes the parent view for this view.\r
+       * Seize this moment to cache the AWT Container I'm in.\r
+       */\r
+       public void setParent(View parent)\r
+       {\r
+               super.setParent(parent);\r
+               fContainer = ((parent != null) ? getContainer() : null);\r
+               if((parent == null) && (fComponent != null))\r
+               {\r
+                       fComponent.getParent().remove(fComponent);\r
+                       fComponent = null;\r
+               }\r
+       }\r
+\r
+       /** My attributes may have changed. */\r
+       public void changedUpdate(DocumentEvent e, Shape a, ViewFactory f)\r
+       {\r
+               super.changedUpdate(e, a, f);\r
+               float align = getVerticalAlignment();\r
+\r
+               int height = fHeight;\r
+               int width  = fWidth;\r
+\r
+               initialize(getElement());\r
+\r
+               boolean hChanged = fHeight != height;\r
+               boolean wChanged = fWidth != width;\r
+               if(hChanged || wChanged || getVerticalAlignment() != align)\r
+               {\r
+                       getParent().preferenceChanged(this, hChanged, wChanged);\r
+               }\r
+       }\r
+\r
+\r
+       /**\r
+         * Paints the image.\r
+         *\r
+         * @param g the rendering surface to use\r
+         * @param a the allocated region to render into\r
+         * @see View#paint\r
+         */\r
+       public void paint(Graphics g, Shape a)\r
+       {\r
+               Color oldColor = g.getColor();\r
+               fBounds = a.getBounds();\r
+               int border = getBorder();\r
+               int x = fBounds.x + border + getSpace(X_AXIS);\r
+               int y = fBounds.y + border + getSpace(Y_AXIS);\r
+               int width = fWidth;\r
+               int height = fHeight;\r
+               int sel = getSelectionState();\r
+\r
+               // If no pixels yet, draw gray outline and icon\r
+               if(!hasPixels(this))\r
+               {\r
+                       g.setColor(Color.lightGray);\r
+                       g.drawRect(x, y, width - 1, height - 1);\r
+                       g.setColor(oldColor);\r
+                       loadImageStatusIcons();\r
+                       Icon icon = ((fImage == null) ? sMissingImageIcon : sPendingImageIcon);\r
+                       if(icon != null)\r
+                       {\r
+                               icon.paintIcon(getContainer(), g, x, y);\r
+                       }\r
+               }\r
+\r
+               // Draw image\r
+               if(fImage != null)\r
+               {\r
+                       g.drawImage(fImage, x, y, width, height, this);\r
+               }\r
+\r
+               // If selected exactly, we need a black border & grow-box\r
+               Color bc = getBorderColor();\r
+               if(sel == 2)\r
+               {\r
+                       // Make sure there's room for a border\r
+                       int delta = 2 - border;\r
+                       if(delta > 0)\r
+                       {\r
+                               x += delta;\r
+                               y += delta;\r
+                               width -= delta << 1;\r
+                               height -= delta << 1;\r
+                               border = 2;\r
+                       }\r
+                       bc = null;\r
+                       g.setColor(Color.black);\r
+                       // Draw grow box\r
+                       g.fillRect(x + width - 5, y + height - 5, 5, 5);\r
+               }\r
+\r
+               // Draw border\r
+               if(border > 0)\r
+               {\r
+                       if(bc != null)\r
+                       {\r
+                               g.setColor(bc);\r
+                       }\r
+                       // Draw a thick rectangle:\r
+                       for(int i = 1; i <= border; i++)\r
+                       {\r
+                               g.drawRect(x - i, y - i, width - 1 + i + i, height - 1 + i + i);\r
+                       }\r
+                       g.setColor(oldColor);\r
+               }\r
+       }\r
+\r
+       /** Request that this view be repainted. Assumes the view is still at its last-drawn location.\r
+         */\r
+       protected void repaint(long delay)\r
+       {\r
+               if((fContainer != null) && (fBounds != null))\r
+               {\r
+                       fContainer.repaint(delay, fBounds.x, fBounds.y, fBounds.width, fBounds.height);\r
+               }\r
+       }\r
+\r
+       /**\r
+         * Determines whether the image is selected, and if it's the only thing selected.\r
+         * @return  0 if not selected, 1 if selected, 2 if exclusively selected.\r
+         * "Exclusive" selection is only returned when editable.\r
+         */\r
+       protected int getSelectionState()\r
+       {\r
+               int p0 = fElement.getStartOffset();\r
+               int p1 = fElement.getEndOffset();\r
+               if(fContainer instanceof JTextComponent)\r
+               {\r
+                       JTextComponent textComp = (JTextComponent)fContainer;\r
+                       int start = textComp.getSelectionStart();\r
+                       int end = textComp.getSelectionEnd();\r
+                       if((start <= p0) && (end >= p1))\r
+                       {\r
+                               if((start == p0) && (end == p1) && isEditable())\r
+                               {\r
+                                       return 2;\r
+                               }\r
+                               else\r
+                               {\r
+                                       return 1;\r
+                               }\r
+                       }\r
+               }\r
+               return 0;\r
+       }\r
+\r
+       protected boolean isEditable()\r
+       {\r
+               return ((fContainer instanceof JEditorPane) && ((JEditorPane)fContainer).isEditable());\r
+       }\r
+\r
+       /** Returns the text editor's highlight color.\r
+         */\r
+       protected Color getHighlightColor()\r
+       {\r
+               JTextComponent textComp = (JTextComponent)fContainer;\r
+               return textComp.getSelectionColor();\r
+       }\r
+\r
+       // Progressive display -------------------------------------------------\r
+\r
+       // This can come on any thread. If we are in the process of reloading\r
+       // the image and determining our state (loading == true) we don't fire\r
+       // preference changed, or repaint, we just reset the fWidth/fHeight as\r
+       // necessary and return. This is ok as we know when loading finishes\r
+       // it will pick up the new height/width, if necessary.\r
+\r
+       private static boolean sIsInc = true;\r
+       private static int sIncRate = 100;\r
+\r
+       public boolean imageUpdate(Image img, int flags, int x, int y, int width, int height)\r
+       {\r
+               if((fImage == null) || (fImage != img))\r
+               {\r
+                       return false;\r
+               }\r
+\r
+               // Bail out if there was an error\r
+               if((flags & (ABORT|ERROR)) != 0)\r
+               {\r
+                       fImage = null;\r
+                       repaint(0);\r
+                       return false;\r
+               }\r
+\r
+               // Resize image if necessary\r
+               short changed = 0;\r
+               if((flags & ImageObserver.HEIGHT) != 0)\r
+               {\r
+                       if(!getElement().getAttributes().isDefined(HTML.Attribute.HEIGHT))\r
+                       {\r
+                               changed |= 1;\r
+                       }\r
+               }\r
+               if((flags & ImageObserver.WIDTH) != 0)\r
+               {\r
+                       if(!getElement().getAttributes().isDefined(HTML.Attribute.WIDTH))\r
+                       {\r
+                               changed |= 2;\r
+                       }\r
+               }\r
+\r
+               synchronized(this)\r
+               {\r
+                       if((changed & 1) == 1)\r
+                       {\r
+                               fWidth = width;\r
+                       }\r
+                       if((changed & 2) == 2)\r
+                       {\r
+                               fHeight = height;\r
+                       }\r
+                       if(bLoading)\r
+                       {\r
+                               // No need to resize or repaint, still in the process of loading\r
+                               return true;\r
+                       }\r
+               }\r
+\r
+               if(changed != 0)\r
+               {\r
+                       // May need to resize myself, asynchronously\r
+                       Document doc = getDocument();\r
+                       try\r
+                       {\r
+                               if(doc instanceof AbstractDocument)\r
+                               {\r
+                                       ((AbstractDocument)doc).readLock();\r
+                               }\r
+                               preferenceChanged(this, true, true);\r
+                       }\r
+                       finally\r
+                       {\r
+                               if(doc instanceof AbstractDocument)\r
+                               {\r
+                                       ((AbstractDocument)doc).readUnlock();\r
+                               }\r
+                       }\r
+                       return true;\r
+               }\r
+\r
+               // Repaint when done or when new pixels arrive\r
+               if((flags & (FRAMEBITS|ALLBITS)) != 0)\r
+               {\r
+                       repaint(0);\r
+               }\r
+               else if((flags & SOMEBITS) != 0)\r
+               {\r
+                       if(sIsInc)\r
+                       {\r
+                               repaint(sIncRate);\r
+                       }\r
+               }\r
+               return ((flags & ALLBITS) == 0);\r
+       }\r
+\r
+       // Layout --------------------------------------------------------------\r
+\r
+       /** Determines the preferred span for this view along an axis.\r
+         *\r
+         * @param axis may be either X_AXIS or Y_AXIS\r
+         * @returns  the span the view would like to be rendered into.\r
+         *           Typically the view is told to render into the span\r
+         *           that is returned, although there is no guarantee.\r
+         *           The parent may choose to resize or break the view.\r
+         */\r
+       public float getPreferredSpan(int axis)\r
+       {\r
+               int extra = 2 * (getBorder() + getSpace(axis));\r
+               switch(axis)\r
+               {\r
+                       case View.X_AXIS:\r
+                               return fWidth+extra;\r
+                       case View.Y_AXIS:\r
+                               return fHeight+extra;\r
+                       default:\r
+                               throw new IllegalArgumentException("Invalid axis in getPreferredSpan() : " + axis);\r
+               }\r
+       }\r
+\r
+       /** Determines the desired alignment for this view along an\r
+         * axis. This is implemented to give the alignment to the\r
+         * bottom of the icon along the y axis, and the default\r
+         * along the x axis.\r
+         *\r
+         * @param axis may be either X_AXIS or Y_AXIS\r
+         * @returns the desired alignment. This should be a value\r
+         *   between 0.0 and 1.0 where 0 indicates alignment at the\r
+         *   origin and 1.0 indicates alignment to the full span\r
+         *   away from the origin. An alignment of 0.5 would be the\r
+         *   center of the view.\r
+         */\r
+       public float getAlignment(int axis)\r
+       {\r
+               switch(axis)\r
+               {\r
+                       case View.Y_AXIS:\r
+                               return getVerticalAlignment();\r
+                       default:\r
+                               return super.getAlignment(axis);\r
+               }\r
+       }\r
+\r
+       /** Provides a mapping from the document model coordinate space\r
+         * to the coordinate space of the view mapped to it.\r
+         *\r
+         * @param pos the position to convert\r
+         * @param a the allocated region to render into\r
+         * @return the bounding box of the given position\r
+         * @exception BadLocationException if the given position does not represent a\r
+         *   valid location in the associated document\r
+         * @see View#modelToView\r
+         */\r
+       public Shape modelToView(int pos, Shape a, Position.Bias b)\r
+       throws BadLocationException\r
+       {\r
+               int p0 = getStartOffset();\r
+               int p1 = getEndOffset();\r
+               if((pos >= p0) && (pos <= p1))\r
+               {\r
+                       Rectangle r = a.getBounds();\r
+                       if(pos == p1)\r
+                       {\r
+                               r.x += r.width;\r
+                       }\r
+                       r.width = 0;\r
+                       return r;\r
+               }\r
+               return null;\r
+       }\r
+\r
+       /** Provides a mapping from the view coordinate space to the logical\r
+         * coordinate space of the model.\r
+         *\r
+         * @param x the X coordinate\r
+         * @param y the Y coordinate\r
+         * @param a the allocated region to render into\r
+         * @return the location within the model that best represents the\r
+         *         given point of view\r
+         * @see View#viewToModel\r
+         */\r
+       public int viewToModel(float x, float y, Shape a, Position.Bias[] bias)\r
+       {\r
+               Rectangle alloc = (Rectangle) a;\r
+               if(x < (alloc.x + alloc.width))\r
+               {\r
+                       bias[0] = Position.Bias.Forward;\r
+                       return getStartOffset();\r
+               }\r
+               bias[0] = Position.Bias.Backward;\r
+               return getEndOffset();\r
+       }\r
+\r
+       /** Change the size of this image. This alters the HEIGHT and WIDTH\r
+         * attributes of the Element and causes a re-layout.\r
+         */\r
+       protected void resize(int width, int height)\r
+       {\r
+               if((width == fWidth) && (height == fHeight))\r
+               {\r
+                       return;\r
+               }\r
+               fWidth = width;\r
+               fHeight= height;\r
+               // Replace attributes in document\r
+               MutableAttributeSet attr = new SimpleAttributeSet();\r
+               attr.addAttribute(HTML.Attribute.WIDTH ,Integer.toString(width));\r
+               attr.addAttribute(HTML.Attribute.HEIGHT,Integer.toString(height));\r
+               ((StyledDocument)getDocument()).setCharacterAttributes(fElement.getStartOffset(), fElement.getEndOffset(), attr, false);\r
+       }\r
+\r
+       // Mouse event handling ------------------------------------------------\r
+\r
+       /** Select or grow image when clicked.\r
+         */\r
+       public void mousePressed(MouseEvent e)\r
+       {\r
+               Dimension size = fComponent.getSize();\r
+               if((e.getX() >= (size.width - 7)) && (e.getY() >= (size.height - 7)) && (getSelectionState() == 2))\r
+               {\r
+                       // Click in selected grow-box:\r
+                       Point loc = fComponent.getLocationOnScreen();\r
+                       fGrowBase = new Point(loc.x + e.getX() - fWidth, loc.y + e.getY() - fHeight);\r
+                       fGrowProportionally = e.isShiftDown();\r
+               }\r
+               else\r
+               {\r
+                       // Else select image:\r
+                       fGrowBase = null;\r
+                       JTextComponent comp = (JTextComponent)fContainer;\r
+                       int start = fElement.getStartOffset();\r
+                       int end = fElement.getEndOffset();\r
+                       int mark = comp.getCaret().getMark();\r
+                       int dot  = comp.getCaret().getDot();\r
+                       if(e.isShiftDown())\r
+                       {\r
+                               // extend selection if shift key down:\r
+                               if(mark <= start)\r
+                               {\r
+                                       comp.moveCaretPosition(end);\r
+                               }\r
+                               else\r
+                               {\r
+                                       comp.moveCaretPosition(start);\r
+                               }\r
+                       }\r
+                       else\r
+                       {\r
+                               // just select image, without shift:\r
+                               if(mark != start)\r
+                               {\r
+                                       comp.setCaretPosition(start);\r
+                               }\r
+                               if(dot != end)\r
+                               {\r
+                                       comp.moveCaretPosition(end);\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+\r
+       /** Resize image if initial click was in grow-box: */\r
+       public void mouseDragged(MouseEvent e)\r
+       {\r
+               if(fGrowBase != null)\r
+               {\r
+                       Point loc = fComponent.getLocationOnScreen();\r
+                       int width = Math.max(2, loc.x + e.getX() - fGrowBase.x);\r
+                       int height= Math.max(2, loc.y + e.getY() - fGrowBase.y);\r
+                       if(e.isShiftDown() && fImage != null)\r
+                       {\r
+                               // Make sure size is proportional to actual image size\r
+                               float imgWidth = fImage.getWidth(this);\r
+                               float imgHeight = fImage.getHeight(this);\r
+                               if((imgWidth > 0) && (imgHeight > 0))\r
+                               {\r
+                                       float prop = imgHeight / imgWidth;\r
+                                       float pwidth = height / prop;\r
+                                       float pheight = width * prop;\r
+                                       if(pwidth > width)\r
+                                       {\r
+                                               width = (int)pwidth;\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               height = (int)pheight;\r
+                                       }\r
+                               }\r
+                       }\r
+                       resize(width,height);\r
+               }\r
+       }\r
+\r
+       public void mouseReleased(MouseEvent me)\r
+       {\r
+               fGrowBase = null;\r
+               //! Should post some command to make the action undo-able\r
+       }\r
+\r
+       /** On double-click, open image properties dialog.\r
+         */\r
+       public void mouseClicked(MouseEvent me)\r
+       {\r
+               if(me.getClickCount() == 2)\r
+               {\r
+                       //$ IMPLEMENT\r
+               }\r
+       }\r
+\r
+       public void mouseEntered(MouseEvent me) { ; }\r
+       public void mouseMoved(MouseEvent me)   { ; }\r
+       public void mouseExited(MouseEvent me)  { ; }\r
+\r
+       // Static icon accessors -----------------------------------------------\r
+\r
+       private Icon makeIcon(final String gifFile)\r
+       throws IOException\r
+       {\r
+               /* Copy resource into a byte array. This is\r
+                * necessary because several browsers consider\r
+                * Class.getResource a security risk because it\r
+                * can be used to load additional classes.\r
+                * Class.getResourceAsStream just returns raw\r
+                * bytes, which we can convert to an image.\r
+                */\r
+               InputStream resource = RelativeImageView.class.getResourceAsStream(gifFile);\r
+\r
+               if(resource == null)\r
+               {\r
+                       return null;\r
+               }\r
+               BufferedInputStream in = new BufferedInputStream(resource);\r
+               ByteArrayOutputStream out = new ByteArrayOutputStream(1024);\r
+               byte[] buffer = new byte[1024];\r
+               int n;\r
+               while((n = in.read(buffer)) > 0)\r
+               {\r
+                       out.write(buffer, 0, n);\r
+               }\r
+               in.close();\r
+               out.flush();\r
+\r
+               buffer = out.toByteArray();\r
+               if(buffer.length == 0)\r
+               {\r
+                       System.err.println("WARNING : " + gifFile + " is zero-length");\r
+                       return null;\r
+               }\r
+               return new ImageIcon(buffer);\r
+       }\r
+\r
+       private void loadImageStatusIcons()\r
+       {\r
+               try\r
+               {\r
+                       if(sPendingImageIcon == null)\r
+                       {\r
+                               sPendingImageIcon = makeIcon(PENDING_IMAGE_SRC);\r
+                       }\r
+                       if(sMissingImageIcon == null)\r
+                       {\r
+                               sMissingImageIcon = makeIcon(MISSING_IMAGE_SRC);\r
+                       }\r
+               }\r
+               catch(Exception e)\r
+               {\r
+                       System.err.println("ImageView : Couldn't load image icons");\r
+               }\r
+       }\r
+\r
+       protected StyleSheet getStyleSheet()\r
+       {\r
+               HTMLDocument doc = (HTMLDocument)getDocument();\r
+               return doc.getStyleSheet();\r
+       }\r
+\r
+}\r
diff --git a/ekit/com/hexidec/ekit/component/SearchDialog.java b/ekit/com/hexidec/ekit/component/SearchDialog.java
new file mode 100644 (file)
index 0000000..cd6623e
--- /dev/null
@@ -0,0 +1,140 @@
+/*\r
+GNU Lesser General Public License\r
+\r
+SearchDialog\r
+Copyright (C) 2000-2003 Howard Kistler\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+*/\r
+\r
+package com.hexidec.ekit.component;\r
+\r
+import java.awt.Frame;\r
+import java.awt.event.WindowAdapter;\r
+import java.awt.event.WindowEvent;\r
+import java.beans.PropertyChangeEvent;\r
+import java.beans.PropertyChangeListener;\r
+import javax.swing.JCheckBox;\r
+import javax.swing.JDialog;\r
+import javax.swing.JOptionPane;\r
+import javax.swing.JTextField;\r
+\r
+import com.hexidec.util.Translatrix;\r
+\r
+/** Class for providing a dialog that lets the user specify arguments for\r
+  * the Search Find/Replace functions\r
+  */\r
+public class SearchDialog extends JDialog\r
+{\r
+       private String inputFindTerm    = (String)null;\r
+       private String inputReplaceTerm = (String)null;\r
+       private boolean bCaseSensitive  = false;\r
+       private boolean bStartAtTop     = false;\r
+       private boolean bReplaceAll     = false;\r
+       private JOptionPane jOptionPane;\r
+\r
+       public SearchDialog(Frame parent, String title, boolean bModal, boolean bIsReplace, boolean bCaseSetting, boolean bTopSetting)\r
+       {\r
+               super(parent, title, bModal);\r
+               final boolean isReplaceDialog    = bIsReplace;\r
+               final JTextField jtxfFindTerm    = new JTextField(3);\r
+               final JTextField jtxfReplaceTerm = new JTextField(3);\r
+               final JCheckBox  jchkCase        = new JCheckBox(Translatrix.getTranslationString("SearchCaseSensitive"), bCaseSetting);\r
+               final JCheckBox  jchkTop         = new JCheckBox(Translatrix.getTranslationString("SearchStartAtTop"), bTopSetting);\r
+               final JCheckBox  jchkAll         = new JCheckBox(Translatrix.getTranslationString("SearchReplaceAll"), false);\r
+               final Object[] buttonLabels      = { Translatrix.getTranslationString("DialogAccept"), Translatrix.getTranslationString("DialogCancel") };\r
+               if(bIsReplace)\r
+               {\r
+                       Object[] panelContents = {\r
+                               Translatrix.getTranslationString("SearchFind"),\r
+                               jtxfFindTerm,\r
+                               Translatrix.getTranslationString("SearchReplace"),\r
+                               jtxfReplaceTerm,\r
+                               jchkAll,\r
+                               jchkCase,\r
+                               jchkTop\r
+                       };\r
+                       jOptionPane = new JOptionPane(panelContents, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION, null, buttonLabels, buttonLabels[0]);\r
+               }\r
+               else\r
+               {\r
+                       Object[] panelContents = {\r
+                               Translatrix.getTranslationString("SearchFind"),\r
+                               jtxfFindTerm,\r
+                               jchkCase,\r
+                               jchkTop\r
+                       };\r
+                       jOptionPane = new JOptionPane(panelContents, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION, null, buttonLabels, buttonLabels[0]);\r
+               }\r
+               setContentPane(jOptionPane);\r
+               setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);\r
+\r
+               addWindowListener(new WindowAdapter() {\r
+                       public void windowClosing(WindowEvent we)\r
+                       {\r
+                               jOptionPane.setValue(new Integer(JOptionPane.CLOSED_OPTION));\r
+                       }\r
+               });\r
+\r
+               jOptionPane.addPropertyChangeListener(new PropertyChangeListener() {\r
+                       public void propertyChange(PropertyChangeEvent e)\r
+                       {\r
+                               String prop = e.getPropertyName();\r
+                               if(isVisible() \r
+                                       && (e.getSource() == jOptionPane)\r
+                                       && (prop.equals(JOptionPane.VALUE_PROPERTY) || prop.equals(JOptionPane.INPUT_VALUE_PROPERTY)))\r
+                               {\r
+                                       Object value = jOptionPane.getValue();\r
+                                       if(value == JOptionPane.UNINITIALIZED_VALUE)\r
+                                       {\r
+                                               return;\r
+                                       }\r
+                                       jOptionPane.setValue(JOptionPane.UNINITIALIZED_VALUE);\r
+                                       if(value.equals(buttonLabels[0]))\r
+                                       {\r
+                                               inputFindTerm  = jtxfFindTerm.getText();\r
+                                               bCaseSensitive = jchkCase.isSelected();\r
+                                               bStartAtTop    = jchkTop.isSelected();\r
+                                               if(isReplaceDialog)\r
+                                               {\r
+                                                       inputReplaceTerm = jtxfReplaceTerm.getText();\r
+                                                       bReplaceAll      = jchkAll.isSelected();\r
+                                               }\r
+                                               setVisible(false);\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               inputFindTerm    = (String)null;\r
+                                               inputReplaceTerm = (String)null;\r
+                                               bCaseSensitive   = false;\r
+                                               bStartAtTop      = false;\r
+                                               bReplaceAll      = false;\r
+                                               setVisible(false);\r
+                                       }\r
+                               }\r
+                       }\r
+               });\r
+               this.pack();\r
+               this.show();\r
+               jtxfFindTerm.requestFocus();\r
+       }\r
+\r
+       public String  getFindTerm()      { return inputFindTerm; }\r
+       public String  getReplaceTerm()   { return inputReplaceTerm; }\r
+       public boolean getCaseSensitive() { return bCaseSensitive; }\r
+       public boolean getStartAtTop()    { return bStartAtTop; }\r
+       public boolean getReplaceAll()    { return bReplaceAll; }\r
+}\r
+\r
diff --git a/ekit/com/hexidec/ekit/component/SimpleInfoDialog.java b/ekit/com/hexidec/ekit/component/SimpleInfoDialog.java
new file mode 100644 (file)
index 0000000..a9ce48d
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+GNU Lesser General Public License
+
+SimpleInfoDialog
+Copyright (C) 2000-2003 Howard Kistler
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+package com.hexidec.ekit.component;
+
+import java.awt.Frame;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import javax.swing.JDialog;
+import javax.swing.JOptionPane;
+
+import com.hexidec.util.Translatrix;
+
+/** Class for providing a dialog that lets the user specify values for tag attributes.
+  */
+public class SimpleInfoDialog extends JDialog
+{
+       public static final int ERROR    = JOptionPane.ERROR_MESSAGE;
+       public static final int INFO     = JOptionPane.INFORMATION_MESSAGE;
+       public static final int WARNING  = JOptionPane.WARNING_MESSAGE;
+       public static final int QUESTION = JOptionPane.QUESTION_MESSAGE;
+       public static final int PLAIN    = JOptionPane.PLAIN_MESSAGE;
+
+       private JOptionPane jOptionPane;
+       private Object[] buttonLabels;
+       private Integer buttonState = new Integer(JOptionPane.CLOSED_OPTION);
+
+       public SimpleInfoDialog(Frame parent, String title, boolean bModal, String message, int type)
+       {
+               super(parent, title, bModal);
+               if(type == QUESTION)
+               {
+                       buttonLabels = new Object[]{ Translatrix.getTranslationString("DialogAccept"), Translatrix.getTranslationString("DialogCancel") };
+                       jOptionPane = new JOptionPane(message, type, JOptionPane.OK_CANCEL_OPTION, null, buttonLabels, buttonLabels[0]);
+               }
+               else
+               {
+                       buttonLabels = new Object[]{ Translatrix.getTranslationString("DialogClose") };
+                       jOptionPane = new JOptionPane(message, type, JOptionPane.DEFAULT_OPTION, null, buttonLabels, buttonLabels[0]);
+               }
+
+               setContentPane(jOptionPane);
+               setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
+
+               jOptionPane.addPropertyChangeListener(new PropertyChangeListener()
+               {
+                       public void propertyChange(PropertyChangeEvent e)
+                       {
+                               String prop = e.getPropertyName();
+                               if(isVisible() && (e.getSource() == jOptionPane) && (prop.equals(JOptionPane.VALUE_PROPERTY) || prop.equals(JOptionPane.INPUT_VALUE_PROPERTY)))
+                               {
+                                       setVisible(false);
+                               }
+                       }
+               });
+
+               this.pack();
+               int centerX = (int)(((parent.getSize().getWidth()  / 2) + parent.getLocation().getX()) - (this.getSize().getWidth()  / 2));
+               int centerY = (int)(((parent.getSize().getHeight() / 2) + parent.getLocation().getY()) - (this.getSize().getHeight() / 2));
+               if(centerX < 0) { centerX = 0; }
+               if(centerY < 0) { centerY = 0; }
+               this.setLocation(centerX, centerY);
+               this.show();
+       }
+
+       public SimpleInfoDialog(Frame parent, String title, boolean bModal, String message)
+       {
+               this(parent, title, bModal, message, WARNING);
+       }
+
+       public String getDecisionValue()
+       {
+               return jOptionPane.getValue().toString();
+       }
+}
diff --git a/ekit/com/hexidec/ekit/component/TableInputDialog.java b/ekit/com/hexidec/ekit/component/TableInputDialog.java
new file mode 100644 (file)
index 0000000..344f978
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+GNU General Public License
+
+TableInputDialog
+Copyright (C) 2000-2003 Howard Kistler
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+package com.hexidec.ekit.component;
+
+import java.awt.Frame;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import javax.swing.JDialog;
+import javax.swing.JOptionPane;
+import javax.swing.JTextField;
+
+import com.hexidec.util.Translatrix;
+
+/** Class for providing a dialog that lets the user specify values for tag attributes
+  */
+public class TableInputDialog extends JDialog
+{
+       private String inputRows   = new String();
+       private String inputCols   = new String();
+       private String inputBorder = new String();
+       private String inputSpace  = new String();
+       private String inputPad    = new String();
+       private JOptionPane jOptionPane;
+
+       public TableInputDialog(Frame parent, String title, boolean bModal)
+       {
+               super(parent, title, bModal);
+               final JTextField jtxfRows   = new JTextField(3);
+               final JTextField jtxfCols   = new JTextField(3);
+               final JTextField jtxfBorder = new JTextField(3);
+               final JTextField jtxfSpace  = new JTextField(3);
+               final JTextField jtxfPad    = new JTextField(3);
+               final Object[] buttonLabels = { Translatrix.getTranslationString("DialogAccept"), Translatrix.getTranslationString("DialogCancel") };
+               Object[] panelContents = {
+                       Translatrix.getTranslationString("TableRows"),        jtxfRows,
+                       Translatrix.getTranslationString("TableColumns"),     jtxfCols,
+                       Translatrix.getTranslationString("TableBorder"),      jtxfBorder,
+                       Translatrix.getTranslationString("TableCellSpacing"), jtxfSpace,
+                       Translatrix.getTranslationString("TableCellPadding"), jtxfPad
+               };
+               jOptionPane = new JOptionPane(panelContents, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION, null, buttonLabels, buttonLabels[0]);
+
+               setContentPane(jOptionPane);
+               setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
+
+               addWindowListener(new WindowAdapter() {
+                       public void windowClosing(WindowEvent we)
+                       {
+                               jOptionPane.setValue(new Integer(JOptionPane.CLOSED_OPTION));
+                       }
+               });
+
+               jOptionPane.addPropertyChangeListener(new PropertyChangeListener() {
+                       public void propertyChange(PropertyChangeEvent e)
+                       {
+                               String prop = e.getPropertyName();
+                               if(isVisible() 
+                                       && (e.getSource() == jOptionPane)
+                                       && (prop.equals(JOptionPane.VALUE_PROPERTY) || prop.equals(JOptionPane.INPUT_VALUE_PROPERTY)))
+                               {
+                                       Object value = jOptionPane.getValue();
+                                       if(value == JOptionPane.UNINITIALIZED_VALUE)
+                                       {
+                                               return;
+                                       }
+                                       jOptionPane.setValue(JOptionPane.UNINITIALIZED_VALUE);
+                                       if(value.equals(buttonLabels[0]))
+                                       {
+                                               inputRows   = jtxfRows.getText();
+                                               inputCols   = jtxfCols.getText();
+                                               inputBorder = jtxfBorder.getText();
+                                               inputSpace  = jtxfSpace.getText();
+                                               inputPad    = jtxfPad.getText();
+                                               setVisible(false);
+                                       }
+                                       else
+                                       {
+                                               inputRows   = "";
+                                               inputCols   = "";
+                                               inputBorder = "";
+                                               inputSpace  = "";
+                                               inputPad    = "";
+                                               setVisible(false);
+                                       }
+                               }
+                       }
+               });
+               this.pack();
+       }
+
+       public int getRows()
+       {
+               try
+               {
+                       return Integer.parseInt(inputRows);
+               }
+               catch(NumberFormatException nfe)
+               {
+                       return -1;
+               }
+       }
+
+       public int getCols()
+       {
+               try
+               {
+                       return Integer.parseInt(inputCols);
+               }
+               catch(NumberFormatException nfe)
+               {
+                       return -1;
+               }
+       }
+
+       public int getBorder()
+       {
+               try
+               {
+                       return Integer.parseInt(inputBorder);
+               }
+               catch(NumberFormatException nfe)
+               {
+                       return -1;
+               }
+       }
+
+       public int getSpacing()
+       {
+               try
+               {
+                       return Integer.parseInt(inputSpace);
+               }
+               catch(NumberFormatException nfe)
+               {
+                       return -1;
+               }
+       }
+
+       public int getPadding()
+       {
+               try
+               {
+                       return Integer.parseInt(inputPad);
+               }
+               catch(NumberFormatException nfe)
+               {
+                       return -1;
+               }
+       }
+}
+
diff --git a/ekit/com/hexidec/ekit/component/UserInputAnchorDialog.java b/ekit/com/hexidec/ekit/component/UserInputAnchorDialog.java
new file mode 100644 (file)
index 0000000..2670194
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+GNU Lesser General Public License
+
+UserInputDialog
+Copyright (C) 2000-2003 Howard Kistler
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+package com.hexidec.ekit.component;
+
+import com.hexidec.ekit.EkitCore;
+import java.awt.Container;
+import java.awt.Frame;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import javax.swing.border.*;
+import javax.swing.BorderFactory;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.SwingConstants;
+import javax.swing.WindowConstants;
+
+public class UserInputAnchorDialog extends JDialog implements ActionListener
+{
+       private EkitCore parentEkit;
+       private String inputText = null;
+       private final JTextField jtxfInput = new JTextField(32);
+
+       public UserInputAnchorDialog(EkitCore peKit, String title, boolean bModal, String defaultAnchor)
+       {               
+               super(peKit.getFrame(), title, bModal);
+               parentEkit = peKit;
+               jtxfInput.setText(defaultAnchor);
+               init();
+       }
+
+       public void actionPerformed(ActionEvent e)
+       {
+               if(e.getActionCommand().equals("accept"))
+               {
+                       inputText = jtxfInput.getText();
+                       setVisible(false);
+               }       
+               if(e.getActionCommand().equals("cancel"))
+               {
+                       inputText = null;
+                       setVisible(false);
+               }
+               else if(e.getActionCommand().equals("files"))
+               {
+                       String selectedFile = parentEkit.insertFile();
+                       if(selectedFile != null)
+                       {
+                               jtxfInput.setText(selectedFile);        
+                       }
+               }
+       }
+
+       public void init()
+       {
+               Container contentPane = getContentPane();
+               contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS));
+               setBounds(100,100,400,300);
+               setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE);
+
+               JPanel centerPanel = new JPanel();
+               centerPanel.setLayout(new BoxLayout(centerPanel, BoxLayout.X_AXIS));
+               JLabel anchorLabel = new JLabel("Anchor:", SwingConstants.LEFT);
+               centerPanel.add(anchorLabel);
+               centerPanel.add(jtxfInput);
+
+               JPanel buttonPanel= new JPanel();               
+               buttonPanel.setBorder(new SoftBevelBorder(BevelBorder.LOWERED));
+
+               JButton saveButton = new JButton("Accept");
+               saveButton.setActionCommand("accept");
+               saveButton.addActionListener(this);
+
+               JButton cancelButton = new JButton("Cancel");
+               cancelButton.setActionCommand("cancel");
+               cancelButton.addActionListener(this);
+
+               JButton filesButton = new JButton("Server Files...");
+               filesButton.setActionCommand("files");
+               filesButton.addActionListener(this);
+
+               buttonPanel.add(saveButton);
+               buttonPanel.add(cancelButton);
+               buttonPanel.add(filesButton);
+
+               contentPane.add(centerPanel);
+               contentPane.add(buttonPanel);
+
+               this.pack();
+               this.setVisible(true);
+       }
+
+       public String getInputText()
+       {
+               return inputText;
+       }
+
+       public void setAnchor(String anchor)
+       {
+               jtxfInput.setText(anchor);
+       }
+
+
+}
+
diff --git a/ekit/com/hexidec/ekit/component/UserInputDialog.java b/ekit/com/hexidec/ekit/component/UserInputDialog.java
new file mode 100644 (file)
index 0000000..95c976f
--- /dev/null
@@ -0,0 +1,113 @@
+/*\r
+GNU Lesser General Public License\r
+\r
+UserInputDialog\r
+Copyright (C) 2000-2003 Howard Kistler\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+*/\r
+\r
+package com.hexidec.ekit.component;\r
+\r
+import java.awt.Frame;\r
+import java.awt.event.ActionEvent;\r
+import java.awt.event.ActionListener;\r
+import java.awt.event.WindowAdapter;\r
+import java.awt.event.WindowEvent;\r
+import java.beans.PropertyChangeEvent;\r
+import java.beans.PropertyChangeListener;\r
+import javax.swing.JDialog;\r
+import javax.swing.JOptionPane;\r
+import javax.swing.JTextField;\r
+\r
+import com.hexidec.util.Translatrix;\r
+\r
+/** Class for providing a dialog that lets the user specify values for tag attributes\r
+  */\r
+public class UserInputDialog extends JDialog\r
+{\r
+\r
+       private String inputText = new String();\r
+       private JOptionPane jOptionPane;\r
+\r
+       public UserInputDialog(Frame parent, String title, boolean bModal, String attribName, String defaultText)\r
+       {\r
+               super(parent, title, bModal);\r
+               final JTextField jtxfInput = new JTextField(32);\r
+               jtxfInput.setText(defaultText);\r
+               Object[] panelContents = { attribName, jtxfInput };\r
+               final Object[] buttonLabels = { Translatrix.getTranslationString("DialogAccept"), Translatrix.getTranslationString("DialogCancel") };\r
+\r
+               jOptionPane = new JOptionPane(panelContents, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION, null, buttonLabels, buttonLabels[0]);\r
+               setContentPane(jOptionPane);\r
+               setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);\r
+\r
+               addWindowListener(new WindowAdapter() {\r
+                       public void windowClosing(WindowEvent we)\r
+                       {\r
+                               jOptionPane.setValue(new Integer(JOptionPane.CLOSED_OPTION));\r
+                       }\r
+               });\r
+\r
+               jtxfInput.addActionListener(new ActionListener() {\r
+                       public void actionPerformed(ActionEvent e)\r
+                       {\r
+                               jOptionPane.setValue(buttonLabels[0]);\r
+                       }\r
+               });\r
+\r
+               jOptionPane.addPropertyChangeListener(new PropertyChangeListener() {\r
+                       public void propertyChange(PropertyChangeEvent e)\r
+                       {\r
+                               String prop = e.getPropertyName();\r
+                               if(isVisible() \r
+                                       && (e.getSource() == jOptionPane)\r
+                                       && (prop.equals(JOptionPane.VALUE_PROPERTY) || prop.equals(JOptionPane.INPUT_VALUE_PROPERTY)))\r
+                               {\r
+                                       Object value = jOptionPane.getValue();\r
+                                       if(value == JOptionPane.UNINITIALIZED_VALUE)\r
+                                       {\r
+                                               return;\r
+                                       }\r
+                                       jOptionPane.setValue(JOptionPane.UNINITIALIZED_VALUE);\r
+                                       if(value.equals(buttonLabels[0]))\r
+                                       {\r
+                                               inputText = jtxfInput.getText();\r
+                                               setVisible(false);\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               inputText = null;\r
+                                               setVisible(false);\r
+                                       }\r
+                               }\r
+                       }\r
+               });\r
+               this.pack();\r
+               this.show();\r
+               jtxfInput.requestFocus();\r
+       }\r
+\r
+       public UserInputDialog(Frame parent, String title, boolean bModal, String attribName)\r
+       {\r
+               this(parent, title, bModal, attribName, "");\r
+       }\r
+\r
+       public String getInputText()\r
+       {\r
+               return inputText;\r
+       }\r
+}\r
+\r
diff --git a/ekit/com/hexidec/ekit/ekit.manifest b/ekit/com/hexidec/ekit/ekit.manifest
new file mode 100644 (file)
index 0000000..1546e74
--- /dev/null
@@ -0,0 +1,6 @@
+Manifest-Version: 1.0
+Specification-Title: Ekit
+Specification-Version: 0.9e
+Implementation-Vendor: hexidec codec (www.hexidec.com) - Howard Kistler
+Main-Class: com/hexidec/ekit/Ekit
+Created-By: 1.3.0 (Sun Microsystems Inc.)
diff --git a/ekit/com/hexidec/ekit/icons/AnchorHK.gif b/ekit/com/hexidec/ekit/icons/AnchorHK.gif
new file mode 100644 (file)
index 0000000..1cf64fe
Binary files /dev/null and b/ekit/com/hexidec/ekit/icons/AnchorHK.gif differ
diff --git a/ekit/com/hexidec/ekit/icons/BoldHK.gif b/ekit/com/hexidec/ekit/icons/BoldHK.gif
new file mode 100644 (file)
index 0000000..5d8efc8
Binary files /dev/null and b/ekit/com/hexidec/ekit/icons/BoldHK.gif differ
diff --git a/ekit/com/hexidec/ekit/icons/ClearFormatHK.gif b/ekit/com/hexidec/ekit/icons/ClearFormatHK.gif
new file mode 100644 (file)
index 0000000..b4f488f
Binary files /dev/null and b/ekit/com/hexidec/ekit/icons/ClearFormatHK.gif differ
diff --git a/ekit/com/hexidec/ekit/icons/CopyHK.gif b/ekit/com/hexidec/ekit/icons/CopyHK.gif
new file mode 100644 (file)
index 0000000..7f88ce8
Binary files /dev/null and b/ekit/com/hexidec/ekit/icons/CopyHK.gif differ
diff --git a/ekit/com/hexidec/ekit/icons/CutHK.gif b/ekit/com/hexidec/ekit/icons/CutHK.gif
new file mode 100644 (file)
index 0000000..57f7c79
Binary files /dev/null and b/ekit/com/hexidec/ekit/icons/CutHK.gif differ
diff --git a/ekit/com/hexidec/ekit/icons/ItalicHK.gif b/ekit/com/hexidec/ekit/icons/ItalicHK.gif
new file mode 100644 (file)
index 0000000..cdb26d8
Binary files /dev/null and b/ekit/com/hexidec/ekit/icons/ItalicHK.gif differ
diff --git a/ekit/com/hexidec/ekit/icons/NewHK.gif b/ekit/com/hexidec/ekit/icons/NewHK.gif
new file mode 100644 (file)
index 0000000..f34bf2c
Binary files /dev/null and b/ekit/com/hexidec/ekit/icons/NewHK.gif differ
diff --git a/ekit/com/hexidec/ekit/icons/OListHK.gif b/ekit/com/hexidec/ekit/icons/OListHK.gif
new file mode 100644 (file)
index 0000000..e170e9e
Binary files /dev/null and b/ekit/com/hexidec/ekit/icons/OListHK.gif differ
diff --git a/ekit/com/hexidec/ekit/icons/OpenHK.gif b/ekit/com/hexidec/ekit/icons/OpenHK.gif
new file mode 100644 (file)
index 0000000..7fa06a6
Binary files /dev/null and b/ekit/com/hexidec/ekit/icons/OpenHK.gif differ
diff --git a/ekit/com/hexidec/ekit/icons/PasteHK.gif b/ekit/com/hexidec/ekit/icons/PasteHK.gif
new file mode 100644 (file)
index 0000000..f765be7
Binary files /dev/null and b/ekit/com/hexidec/ekit/icons/PasteHK.gif differ
diff --git a/ekit/com/hexidec/ekit/icons/SaveHK.gif b/ekit/com/hexidec/ekit/icons/SaveHK.gif
new file mode 100644 (file)
index 0000000..c337443
Binary files /dev/null and b/ekit/com/hexidec/ekit/icons/SaveHK.gif differ
diff --git a/ekit/com/hexidec/ekit/icons/SourceHK.gif b/ekit/com/hexidec/ekit/icons/SourceHK.gif
new file mode 100644 (file)
index 0000000..9c35343
Binary files /dev/null and b/ekit/com/hexidec/ekit/icons/SourceHK.gif differ
diff --git a/ekit/com/hexidec/ekit/icons/StrikeHK.gif b/ekit/com/hexidec/ekit/icons/StrikeHK.gif
new file mode 100644 (file)
index 0000000..8d67e5d
Binary files /dev/null and b/ekit/com/hexidec/ekit/icons/StrikeHK.gif differ
diff --git a/ekit/com/hexidec/ekit/icons/SubHK.gif b/ekit/com/hexidec/ekit/icons/SubHK.gif
new file mode 100644 (file)
index 0000000..074ff5a
Binary files /dev/null and b/ekit/com/hexidec/ekit/icons/SubHK.gif differ
diff --git a/ekit/com/hexidec/ekit/icons/SuperHK.gif b/ekit/com/hexidec/ekit/icons/SuperHK.gif
new file mode 100644 (file)
index 0000000..bcff741
Binary files /dev/null and b/ekit/com/hexidec/ekit/icons/SuperHK.gif differ
diff --git a/ekit/com/hexidec/ekit/icons/UListHK.gif b/ekit/com/hexidec/ekit/icons/UListHK.gif
new file mode 100644 (file)
index 0000000..a568355
Binary files /dev/null and b/ekit/com/hexidec/ekit/icons/UListHK.gif differ
diff --git a/ekit/com/hexidec/ekit/icons/UnderlineHK.gif b/ekit/com/hexidec/ekit/icons/UnderlineHK.gif
new file mode 100644 (file)
index 0000000..ef7be7f
Binary files /dev/null and b/ekit/com/hexidec/ekit/icons/UnderlineHK.gif differ
diff --git a/ekit/com/hexidec/ekit/materials/FAQ_Factory/TaggingDriver/TaggingDriverServlet.java b/ekit/com/hexidec/ekit/materials/FAQ_Factory/TaggingDriver/TaggingDriverServlet.java
new file mode 100644 (file)
index 0000000..b0dcc24
--- /dev/null
@@ -0,0 +1,585 @@
+//{{SERVLET_IMPORT_STMTS\r\r
+package FAQ_Factory.TaggingDriver;\r\r
+import versata.vfc.html.*;\r\r
+import versata.vfc.html.servlet.*;\r\r
+import versata.vfc.html.common.*;\r\r
+import versata.common.*;\r\r
+import versata.vls.*;\r\r
+import java.util.*;\r\r
+import java.math.BigDecimal;\r\r
+import java.io.*;\r\r
+import javax.servlet.*;\r\r
+import javax.servlet.http.*;\r\r
+import java.rmi.RemoteException;\r\r
+\r\r
+//END_SERVLET_IMPORT_STMTS}}\r\r
+import support.*;\r
+\r\r
+//{{SERVLET_CLASS_DECL\r\r
+public class TaggingDriverServlet extends TaggingDriverBaseServlet\r\r
+//END_SERVLET_CLASS_DECL}}\r\r
+{\r\r
+       JustAskConstants constants = new JustAskConstants();\r
+       //private static final String[] legalImageExtensions = \r
+       //  new String[] { ".bmp", ".emf", ".gif", ".jpg", ".pcx", ".psp", ".tif", ".tiff", ".wmf", ".wpg" };\r
+       //private static final String[] legalFileExtensions = \r
+       //  new String[] { ".doc", ".htm", ".pdf", ".txt" };\r
+   // TaggingDriverServlet Class Constructor\r\r
+       //{{SERVLET_CLASS_CTOR\r\r
+       public TaggingDriverServlet ()\r\r
+       //END_SERVLET_CLASS_CTOR}}\r\r
+    {\r\r
+               super();\r\r
+       }\r\r
+       \r\r
+       public void loadLoginPage(boolean failed, HttpServletResponse res, HttpServletRequest req, String msg)\r\r
+               throws IOException \r\r
+       {\r\r
+               //{{SERVLET_LOADLOGINPAGE\r\r
+               // Load login page. If previous attempt failed, load page with failed message.\r\r
+               // This method will be generated in gen'd servlet and user can\r\r
+               // add code for custom login there, or it can be gen'd to supress login\r\r
+               super.loadLoginPage(failed, res, req,msg);\r\r
+               PrintWriter toClient = res.getWriter();\r\r
+               String params = req.getQueryString();\r\r
+               \r\r
+               //END_SERVLET_LOADLOGINPAGE}}\r\r
+    }\r\r
+\r\r
+\r\r
+    public String getFileLocation()\r\r
+    {\r\r
+           return getDefaultFileLocation();\r\r
+       \r\r
+    }\r\r
+\r\r
+    public String getBaseURL(HttpServletRequest req, String packageName, String clientAppName)\r\r
+   {\r\r
+          return super.getBaseURL(req, packageName, clientAppName);\r\r
+    }\r\r
+    public String getServletURL(HttpServletRequest req)\r\r
+    {\r\r
+           return HttpUtils.getRequestURL(req).toString();\r\r
+       \r\r
+    }\r\r
+\r\r
+       public PLSORBSession doLogin(HttpServletRequest req)\r\r
+               throws TierSessionLimitException, RemoteException\r\r
+       {\r\r
+               return doDefaultLogin(req);\r\r
+       }\r\r
+\r\r
+       public void loadStartPage()\r\r
+       {\r\r
+               // Right now, this is done by calling session.start, which calls app.start.\r\r
+               // We may want this here for the case when developer wants to customize.\r\r
+       }\r
+       \r
+///////////////////////////////////////////////////////////////////\r\r
+       // This method handles the POST'ing of form data.\r\r
+       // This is for the purpose of allowing users to have INPUT controls\r\r
+       // of type FILE. When a form contains such a control, the data must be\r\r
+       // posted in multipart format, which Jade does not handle by default.\r\r
+       // The strategy is to catch the POST. If it is a regular post, just pass\r\r
+       // it to super. \r\r
+       // If it is a multipart post, we parse the binary stream and build a new\r\r
+       // HttpServletRequest containing all the parameters except of course\r\r
+       // the contents of the files, and submit that request to super.\r\r
+       //\r\r
+       // Remember that this method is invoked for every post, i.e. anytime the\r\r
+       // user clicks any button. Since we typically want special action only\r\r
+       // for a save, we look at the query_string parameter to determine whether\r\r
+       // the query is a save query. If it's not, we ignore all the file-related\r\r
+       // fields.\r\r
+       //\r\r
+       // The form can have any number of FILE inputs. For each such input, this\r\r
+       // will read the file into a temporary file. The name of that temporary file\r\r
+       // will be put in a field whose is that of the FILE input with "_ServerFileName"\r\r
+       // appended. The name of the file on the client will be put in a field whose\r\r
+       // name is that of the FILE input with "_ClientFileName" appended.\r\r
+       //\r\r
+       // Note that there is no way (apparently) to set the value of a FILE input,\r\r
+       // which is why the client-side file name is returned in a separate field.\r\r
+                       public void doPost(javax.servlet.http.HttpServletRequest req,\r\r
+                          javax.servlet.http.HttpServletResponse res)\r\r
+                           throws javax.servlet.ServletException,\r\r
+                                          java.io.IOException\r\r
+       {\r
+               String contentType = req.getContentType();\r\r
+               //String postedOrgID = "didntgetit";\r\r
+               //boolean gotStartOfOrg = false;\r\r
+               // If this is a regular POST, let super handle it\r\r
+               if(contentType.startsWith("application/x-www-form-urlencoded"))\r\r
+               {\r\r
+                       super.doPost(req, res);\r\r
+                       return;\r\r
+               }\r\r
+                                                                                                                               // If it's not a regular post, it better be multipart\r\r
+               if( ! contentType.startsWith("multipart/form-data"))\r\r
+               {\r\r
+                       throw new ServletException("POST content type was neither "\r\r
+                       + "application/x-www-form-urlencoded nor "\r\r
+                       + "multipart/form-data, which is impossible");\r\r
+               }\r\r
+               // Figure out the directory where the images are placed\r
+               String tmpDir = constants.getImageDir();\r
+//             String tmpDir = "C:\\Program Files\\Vision\\Jade4.1\\JWS\\public_html\\FAQ_Factory\\FAQ\\images\\";\r\r
+               System.err.println("**Temporary dir is : " + tmpDir);\r\r
+               // First read the separator from the contentType, which looks\r\r
+               // like "multipart/form-data; boundary=---------------------------7cf3065520250"\r\r
+               // Be careful : the number of dashes is not exactly as shown in the\r\r
+               // contentType, it actually has two more\r\r
+               int sepIndex = contentType.lastIndexOf('=');\r\r
+               if(sepIndex == -1)\r\r
+                       throw new ServletException("Multipart POST does not have " +\r\r
+                               "a valid contentType");\r\r
+               String separator = contentType.substring(sepIndex + 1);\r\r
+               if( ! separator.startsWith("----------"))\r\r
+                       throw new ServletException("Multipart POST contentType "\r\r
+                               + "does not have a valid separator");\r\r
+               separator = "--" + separator;\r\r
+               System.out.println("***Separator is : " + separator);\r\r
+                               // We store the name and value of all the parameters in this\r\r
+               // hashtable, which is then given to the FileServletRequest.\r\r
+               Hashtable reqHash = new Hashtable();\r\r
+               // Read the total length of the binary stream, we'll use that\r\r
+               // to make sure we're reading the right amount.\r\r
+               // Note : this can be -1 in some cases, in which case\r\r
+               // you just have to read 'til you can't read no more\r\r
+               int contentLength = req.getContentLength();\r\r
+               System.out.println("***getContentLength: " + contentLength);\r\r
+               // Now read the parameters. Each parameter has the format :\r\r
+               // Separator :  -----123456\r\r
+               // Parameter name\r\r
+               // Blank line\r\r
+               // Parameter value (can be multiple lines, ends with next separator)\r\r
+               // The last parameter ends with a separator.\r\r
+               System.out.println("***InputStream :");\r\r
+               ServletInputStream inStr = req.getInputStream();\r\r
+               byte buf[] = new byte[1000];\r\r
+               int byteCount = 0;\r\r
+               int numRead;\r\r
+               String currentAttribName;\r\r
+               boolean isSaveQuery = false;\r
+               boolean isUnique = true;\r
+               boolean isDocManage = false;\r\r
+               // Read the first separator\r\r
+               numRead = inStr.readLine(buf, 0, 1000);\r\r
+               byteCount += numRead;\r\r
+               String strLine = new String(buf, 0, numRead);\r\r
+               if( ! strLine.startsWith(separator))\r\r
+               {\r\r
+                       throw new ServletException("POST does not "\r\r
+                               + "start with separator line, byte " + byteCount);\r\r
+               }\r\r
+               // Now go over the parameters\r\r
+               while (numRead > 0)\r\r
+               {\r\r
+               // Last one ? ContentLength could be -1\r\r
+                       if(byteCount == contentLength)\r\r
+                               break;\r\r
+                       // Read the raw parameter name\r\r
+                       numRead = inStr.readLine(buf, 0, 1000);\r\r
+                       if(numRead == -1)\r\r
+                               break;\r\r
+                       byteCount += numRead;\r\r
+                       strLine = new String(buf, 0, numRead);\r\r
+                       System.out.println("***Raw parameter name : " + strLine);\r\r
+                       // Figure out if the parameter is a FILE input. The name of\r\r
+                       // the parameter looks like :\r\r
+                       // Content-Disposition: form-data; name="txtT1DocName"\r\r
+                       // or in the case of a file parameter :\r\r
+                       // Content-Disposition: form-data; name="fileContents"; filename="c:\temp\foo.txt"\r\r
+                       boolean isFileAttrib = false;\r\r
+                       int semiColIndex = strLine.lastIndexOf(';');\r\r
+                       if(semiColIndex == -1)\r\r
+                               throw new ServletException("POST - bad parameter name");\r\r
+                       String localFileName = "";\r\r
+                       String newLocalFileName = "";\r
+\r\r
+                       if(strLine.substring(semiColIndex, semiColIndex + 6).compareTo("; file") == 0)\r\r
+                       {\r\r
+                               isFileAttrib = true;\r\r
+                               int filenameIndex = strLine.lastIndexOf("; filename=\"");\r\r
+                               //if(filenameIndex == -1)\r\r
+                               //      throw new ServletException("POST : no local file name");\r\r
+                               localFileName = strLine.substring(filenameIndex + 12,\r\r
+                                       strLine.length() - 3);\r\r
+                               System.out.println("**Param is a file, local file : " + localFileName);\r\r
+                               if(localFileName.length() == 0)\r\r
+                               {\r\r
+                                       System.out.println("***There is no file name");\r\r
+//                                     localFileName = "xyz";\r\r
+//                                     isFileAttrib = false;\r
+//                                     break;\r\r
+                               }\r\r
+                       // JGW\r\r
+                       // after we have the local file name. Just pull out the filename and append a rnd\r\r
+                       // value to the file\r\r
+                       int lastdash = 0;\r\r
+                       int lfl = localFileName.length();\r\r
+                       for (int ctr=1; ctr < (lfl - 3); ctr++)\r\r
+                       {\r\r
+                               if(localFileName.substring(ctr,ctr+1).compareTo("\\") == 0)\r\r
+                               {\r\r
+                                       System.out.println("++++lastdash = "+ctr);      \r\r
+                                       lastdash = ctr;\r\r
+                               }\r\r
+                               System.out.println(ctr + " " +lfl);\r\r
+                       }\r
+                       int subval = 0;\r
+                       if(lastdash == 0)\r\r
+                               subval = localFileName.length();\r
+                       else\r
+                               subval = (localFileName.length() - lastdash) - 1;\r\r
+\r\r
+                       if(localFileName.length() > 0)\r\r
+                       {\r\r
+                               File fp = null;                         \r
+                               newLocalFileName = localFileName.substring(lfl - subval, lfl);\r\r
+                               // end JGW\r
+                               fp = new File(tmpDir + newLocalFileName);\r
+                               if(fp.exists() && !isDocManage)\r
+                               {       \r
+                                       res.setContentType("text/html");\r\r
+\r\r
+                                       PrintWriter toClient = res.getWriter();\r\r
+\r\r
+                                       String myJscript ="<h3><center><script language=Javascript>";\r\r
+                                       myJscript = myJscript + " alert('This file already exists.');"; \r\r
+                                       myJscript = myJscript + " </script>";\r\r
+                                       myJscript = myJscript + " </center></h3>";\r\r
+\r\r
+                                       toClient.println(myJscript);\r\r
+\r
+                                       isUnique = false;\r
+                               }\r
+                       }                               \r\r
+               }                       \r\r
+                       // Extract the name of the parameter from the line\r\r
+                       int openQuoteIndex = strLine.indexOf('=') + 2;\r\r
+                       if(openQuoteIndex == -1)\r\r
+                               throw new ServletException("POST : could not find "\r\r
+                                       + "beginning of name of parameter");\r\r
+                       int closeQuoteIndex = strLine.indexOf('"', openQuoteIndex);\r\r
+                       if(closeQuoteIndex == -1)\r\r
+                               throw new ServletException("POST : could not find "\r\r
+                                       + "end of name of parameter");\r\r
+                       currentAttribName = strLine.substring(openQuoteIndex, closeQuoteIndex);\r\r
+                       System.out.println("***New attrib name : " + currentAttribName);\r\r
+                       // Different behavior between Netscape and IE : IE will\r\r
+                       // still send a content type descriptor if there is no file,\r\r
+                       // but Netscape won't.\r\r
+                       // Our strategy to cope with this is, if the file name is empty,\r\r
+                       // we just skip over the contents of the file parameter\r\r
+                       if(isFileAttrib && (localFileName.length() == 0))\r\r
+                       {\r\r
+                               while (true)\r\r
+                               {\r\r
+                                       // Ignore everything until the market\r\r
+                                       byte buf2[] = new byte[1000];\r\r
+                                       int numRead2 = inStr.readLine(buf2, 0, 1000);\r\r
+                                       byteCount += numRead2;\r\r
+                                       String attVal2 = new String(buf2, 0, numRead2);\r\r
+                                       if(attVal2.startsWith(separator))\r\r
+                                               break;\r\r
+                               }\r\r
+                       }\r\r
+                       // Read the value. If it's a file, there could be a\r\r
+                       // massive amount of data\r\r
+                       else if(isFileAttrib && (localFileName.length() > 0))\r\r
+                       {\r\r
+                               // Read the content type descriptor\r\r
+                               numRead = inStr.readLine(buf, 0, 1000);\r\r
+                               byteCount += numRead;\r\r
+                               strLine = new String(buf, 0, numRead);\r\r
+                               if( ! strLine.startsWith("Content-Type:"))\r\r
+                               {\r\r
+                                       throw new ServletException("POST : expected content type "\r\r
+                                               + "descriptor");\r\r
+                               }\r\r
+                               // Read the blank line\r\r
+                               numRead = inStr.readLine(buf, 0, 1000);\r\r
+                               byteCount += numRead;\r\r
+                               if(numRead > 2)\r\r
+                               {\r\r
+                                       throw new ServletException("POST : unexpected data in "\r\r
+                                               + "file parameter line (not blank)");\r\r
+                               }\r\r
+\r
+                               String fullFileName = tmpDir + newLocalFileName;\r\r
+                               System.out.println("**Reading file attribute into : " + fullFileName);                          \r\r
+                               BufferedOutputStream outFile = null;\r\r
+                               try {\r\r
+                                       if(isSaveQuery && isUnique)\r\r
+                                       {\r\r
+                                               FileOutputStream outStr = new FileOutputStream(fullFileName);\r\r
+                                               outFile = new BufferedOutputStream(outStr);\r\r
+                                       }\r\r
+                               }\r\r
+                               catch (IOException e)\r\r
+                               {\r\r
+                                       throw new ServletException("POST : error while opening data file : " + fullFileName);\r\r
+                               }\r\r
+                               numRead = inStr.readLine(buf, 0, 1000);\r\r
+                               while (true)\r\r
+                               {\r\r
+                                       //System.out.println("**Reading file value");\r\r
+                                       byteCount += numRead;\r\r
+                                       if(numRead < 0)\r\r
+                                       throw new ServletException("POST : data for file "\r\r
+                                                       + "was incomplete");\r\r
+                                       byte buf2[] = new byte[1000];\r\r
+                                       int numRead2 = inStr.readLine(buf2, 0, 1000);\r\r
+                                       String attVal2 = new String(buf2, 0, numRead2);\r\r
+                                       // If this is the last line (because it's followed\r\r
+                                       // by a separator), trim off the last CR/LF\r\r
+                                       if(attVal2.startsWith(separator))\r\r
+                                       {\r\r
+                                               if(isSaveQuery && isUnique)\r\r
+                                               {\r\r
+                                                       outFile.write(buf, 0, numRead - 2);\r\r
+                                                       outFile.flush();\r\r
+                                               }\r\r
+                                               break;\r\r
+                                       }\r\r
+                                       else\r\r
+                                       {\r\r
+                                               if(isSaveQuery && isUnique)\r\r
+                                               {\r\r
+                                                       outFile.write(buf, 0, numRead);\r\r
+                                                       outFile.flush();\r\r
+                                               }\r\r
+                                       }\r\r
+                                       buf = buf2; // Thank goodness for garbage collection !\r\r
+                                       numRead = numRead2;\r\r
+                               }\r\r
+                               // Save the name of the file into the parameter\r\r
+                               if(isSaveQuery)\r\r
+                               {\r\r
+                                       // The value doesn't make it back into the file input\r\r
+                                       reqHash.put(currentAttribName, localFileName);\r\r
+                                       reqHash.put(currentAttribName + "_ClientFileName", localFileName);\r\r
+                                       reqHash.put(currentAttribName + "_ServerFileName", fullFileName);\r\r
+                               }\r\r
+                       }\r\r
+                       else // Not a file : just a regular parameter\r\r
+                       {\r\r
+                               System.out.println("***Reading value of parameter");\r\r
+                               // Read the blank line\r\r
+                               numRead = inStr.readLine(buf, 0, 1000);\r\r
+                               byteCount += numRead;\r\r
+                               String s = new String(buf, 0, numRead);\r\r
+                               System.out.println("**First param value line : " + s);\r\r
+                               if(numRead > 2)\r\r
+                               {\r\r
+                                       throw new ServletException("POST : unexpected data in "\r\r
+                                               + "parameter line (not blank)");\r\r
+                               }\r\r
+                               numRead = inStr.readLine(buf, 0, 1000);\r\r
+                               String attVal = "";\r\r
+                               // Is this a Save query ? Remember that for processing of files\r\r
+                               String tmpVal = new String(buf, 0, numRead);\r\r
+                               if(tmpVal.indexOf("UploadFile=") != -1)\r\r
+                               {\r\r
+                                       System.out.println("***********************************This is a save query");\r\r
+                                       isSaveQuery = true;\r\r
+                               }\r\r
+                               while (true)\r\r
+                               {\r\r
+                                       System.out.println("**Reading parameter value");\r\r
+                                       byteCount += numRead;\r\r
+                                       if(numRead < 0)\r\r
+                                               throw new ServletException("POST : data for parameter "\r\r
+                                                       + "was incomplete");\r\r
+                                       byte buf2[] = new byte[1000];\r\r
+                                       int numRead2 = inStr.readLine(buf2, 0, 1000);\r\r
+                                       String attVal2 = new String(buf2, 0, numRead2);\r\r
+                                       // If this is the last line (because it's followed\r\r
+                                       // by a separator), trim off the last CR/LF\r\r
+                                       if(attVal2.startsWith(separator))\r\r
+                                       {\r\r
+                                               attVal += new String(buf, 0, numRead - 2);\r\r
+                                               break;\r\r
+                                       }\r\r
+                                       else\r\r
+                                       {\r\r
+                                               attVal += new String(buf, 0, numRead);\r\r
+                                       }\r\r
+                                       buf = buf2; // Thank goodness for garbage collection !\r\r
+                                       numRead = numRead2;\r\r
+                               }\r\r
+                               // Skip the pseudo-fields that are filled with the\r\r
+                               // names of the file\r\r
+                               if(isSaveQuery)\r\r
+                               {\r\r
+                                       if( ! ((currentAttribName.endsWith("_ClientFileName")) ||\r\r
+                                               (currentAttribName.endsWith("_ServerFileName"))))\r\r
+                                       {\r\r
+                                               reqHash.put(currentAttribName, attVal);\r\r
+                                       }\r\r
+                               }\r\r
+                               else\r
+                               {\r\r
+                                       reqHash.put(currentAttribName, attVal);\r
+                               }\r\r
+                               System.out.println("**New attrib val : " + attVal);\r
+                               if(attVal.length() > 5 && attVal.substring(0,6).equals("sysdir"))\r
+                               {\r
+                                       int endIndex = attVal.indexOf('&');\r
+                                       System.out.println("sysdir " + attVal.substring(7,endIndex) + "\\");\r
+                                       tmpDir = tmpDir + attVal.substring(7,endIndex) + "\\";\r
+\r
+                                       if(attVal.substring(7,endIndex).indexOf("/") != -1)\r
+                                               isDocManage = true;\r
+                                       System.out.println("dir " + tmpDir);\r
+                                       System.out.println("doc management " + isDocManage);\r
+                                       File fp = new File(tmpDir);\r
+                                       if(!fp.exists())\r
+                                       {\r
+                                               System.out.println("doesn't exist");\r
+                                               fp.mkdirs();\r
+                                               System.out.println("created");\r
+                                       }\r
+                               }       \r\r
+                       }\r\r
+               }\r
+               if(!isUnique)\r\r
+               {\r\r
+                       reqHash.put("txtT1ImageUpload", "");\r\r
+               }\r\r
+               System.out.println("***End of InputStream : bytes " + byteCount);\r\r
+               System.out.println("***req " + req.toString());\r
+               System.out.println("***hash " + reqHash.toString());\r\r
+               FileServletRequest newRequest = new FileServletRequest(req, reqHash);\r\r
+               super.doPost(newRequest, res);\r\r
+       }\r
+       \r
+       public void doGet(javax.servlet.http.HttpServletRequest req,\r\r
+                          javax.servlet.http.HttpServletResponse res)\r
+                           throws javax.servlet.ServletException,\r\r
+                                          java.io.IOException\r\r
+       {\r
+               if(req.getParameter("GetImages") != null  &&\r
+                       req.getParameter("ImageExtensions") != null)\r
+               {\r
+                       // Get the image extensions from the request\r
+                       Vector legalImageExtensions = new Vector();\r
+                       StringTokenizer tok = new StringTokenizer(req.getParameter("ImageExtensions"), ":");\r\r
+                       while (tok.hasMoreTokens())\r
+                       {\r
+                               legalImageExtensions.addElement(tok.nextToken());\r
+                       }                                       \r
+                                       \r\r
+                       // Return the directory listing\r
+                       String currentSystem = req.getParameter("GetImages");\r
+                       ObjectOutputStream out = new ObjectOutputStream(res.getOutputStream());\r
+                       File dir = new File(constants.getImageDir() + currentSystem);\r
+                                                                       // For some reason implementing a FileNameFilter throws an IO exception\r
+                       // even if it only returns true.  So we implement one ourselves.\r\r
+                       String[] validImageFiles = getValidImageFiles(dir.list(), legalImageExtensions);\r
+                       if(validImageFiles != null)\r
+                       {\r\r
+                               out.writeObject(validImageFiles);\r
+                       }\r\r
+                       out.flush();\r\r
+                       out.close();\r\r
+               }\r
+               else if(req.getParameter("GetFiles") != null &&\r
+                       req.getParameter("FileExtensions") != null)\r
+               {\r
+                       // Get the file extensions from the request\r
+                       Vector legalFileExtensions = new Vector();\r
+                       StringTokenizer tok = new StringTokenizer(req.getParameter("FileExtensions"), ":");\r\r
+                       while (tok.hasMoreTokens())\r
+                       {\r
+                               legalFileExtensions.addElement(tok.nextToken());\r
+                       }\r
+                                                               \r
+                       // Return the directory listing\r
+                       String currentSystem = req.getParameter("GetFiles");\r
+                       ObjectOutputStream out = new ObjectOutputStream(res.getOutputStream());\r
+                       File dir = new File(constants.getImageDir() + currentSystem);\r
+                       // For some reason implementing a FileNameFilter throws an IO exception\r
+                       // even if it only returns true.  So we implement one ourselves.\r\r
+                       String[] validFiles = getValidFiles(dir.list(), legalFileExtensions);\r
+                       if(validFiles != null)\r
+                       {\r\r
+                               out.writeObject(validFiles);\r
+                       }\r\r
+                       out.flush();\r\r
+                       out.close();\r\r
+               }\r
+               else\r
+               {\r
+                       super.doGet(req, res);\r
+               }\r
+       }\r
+       \r
+       private String[] getValidImageFiles(String[] files, Vector legalImageExtensions)\r
+       {\r
+\r
+               Vector validImageVector = new Vector();\r
+               for ( int fileIndex=0; fileIndex < files.length; fileIndex++)\r
+               {\r
+                       for ( int i=0; i < legalImageExtensions.size(); i++)\r
+                       {\r
+                               if(files[fileIndex].endsWith((String)legalImageExtensions.elementAt(i)))\r
+                               {\r
+                                       validImageVector.addElement(files[fileIndex]);\r
+                                       break;\r
+                               }\r
+                       }\r
+               }\r
+               if(validImageVector.isEmpty())\r
+               {\r
+                       return null;\r
+               }\r
+               else\r
+               {\r
+                       String[] result = new String[validImageVector.size()];\r
+                       int i2 = 0;\r
+                       Enumeration theFiles = validImageVector.elements();\r
+                       while (theFiles.hasMoreElements())\r
+                       {\r
+                               result[i2++] = ((String)theFiles.nextElement());\r
+                       }\r
+                                       return result;\r
+               }\r
+       }\r\r
+\r\r
+       private String[] getValidFiles(String[] files, Vector legalFileExtensions)\r
+       {\r
+\r
+               Vector validFileVector = new Vector();\r
+               for ( int fileIndex=0; fileIndex < files.length; fileIndex++)\r
+               {\r
+                       for ( int i=0; i < legalFileExtensions.size(); i++)\r
+                       {\r
+                               if(files[fileIndex].endsWith((String)legalFileExtensions.elementAt(i)))\r
+                               {\r
+                                       validFileVector.addElement(files[fileIndex]);\r
+                                       break;\r
+                               }\r
+                       }\r
+               }\r
+               if(validFileVector.isEmpty())\r
+               {\r
+                       return null;\r
+               }\r
+               else\r
+               {\r
+                       String[] result = new String[validFileVector.size()];\r
+                       int i2 = 0;\r
+                       Enumeration theFiles = validFileVector.elements();\r
+                       while (theFiles.hasMoreElements())\r
+                       {\r
+                               result[i2++] = ((String)theFiles.nextElement());\r
+                       }\r
+                                       return result;\r
+               }\r
+       }\r\r
+\r\r
+\r\r
+}\r
+\r
diff --git a/ekit/com/hexidec/ekit/materials/LGPL b/ekit/com/hexidec/ekit/materials/LGPL
new file mode 100644 (file)
index 0000000..03851a3
--- /dev/null
@@ -0,0 +1,504 @@
+                 GNU LESSER GENERAL PUBLIC LICENSE\r
+                      Version 2.1, February 1999\r
+\r
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.\r
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ Everyone is permitted to copy and distribute verbatim copies\r
+ of this license document, but changing it is not allowed.\r
+\r
+[This is the first released version of the Lesser GPL.  It also counts\r
+ as the successor of the GNU Library Public License, version 2, hence\r
+ the version number 2.1.]\r
+\r
+                           Preamble\r
+\r
+  The licenses for most software are designed to take away your\r
+freedom to share and change it.  By contrast, the GNU General Public\r
+Licenses are intended to guarantee your freedom to share and change\r
+free software--to make sure the software is free for all its users.\r
+\r
+  This license, the Lesser General Public License, applies to some\r
+specially designated software packages--typically libraries--of the\r
+Free Software Foundation and other authors who decide to use it.  You\r
+can use it too, but we suggest you first think carefully about whether\r
+this license or the ordinary General Public License is the better\r
+strategy to use in any particular case, based on the explanations below.\r
+\r
+  When we speak of free software, we are referring to freedom of use,\r
+not price.  Our General Public Licenses are designed to make sure that\r
+you have the freedom to distribute copies of free software (and charge\r
+for this service if you wish); that you receive source code or can get\r
+it if you want it; that you can change the software and use pieces of\r
+it in new free programs; and that you are informed that you can do\r
+these things.\r
+\r
+  To protect your rights, we need to make restrictions that forbid\r
+distributors to deny you these rights or to ask you to surrender these\r
+rights.  These restrictions translate to certain responsibilities for\r
+you if you distribute copies of the library or if you modify it.\r
+\r
+  For example, if you distribute copies of the library, whether gratis\r
+or for a fee, you must give the recipients all the rights that we gave\r
+you.  You must make sure that they, too, receive or can get the source\r
+code.  If you link other code with the library, you must provide\r
+complete object files to the recipients, so that they can relink them\r
+with the library after making changes to the library and recompiling\r
+it.  And you must show them these terms so they know their rights.\r
+\r
+  We protect your rights with a two-step method: (1) we copyright the\r
+library, and (2) we offer you this license, which gives you legal\r
+permission to copy, distribute and/or modify the library.\r
+\r
+  To protect each distributor, we want to make it very clear that\r
+there is no warranty for the free library.  Also, if the library is\r
+modified by someone else and passed on, the recipients should know\r
+that what they have is not the original version, so that the original\r
+author's reputation will not be affected by problems that might be\r
+introduced by others.\r
+\r
+  Finally, software patents pose a constant threat to the existence of\r
+any free program.  We wish to make sure that a company cannot\r
+effectively restrict the users of a free program by obtaining a\r
+restrictive license from a patent holder.  Therefore, we insist that\r
+any patent license obtained for a version of the library must be\r
+consistent with the full freedom of use specified in this license.\r
+\r
+  Most GNU software, including some libraries, is covered by the\r
+ordinary GNU General Public License.  This license, the GNU Lesser\r
+General Public License, applies to certain designated libraries, and\r
+is quite different from the ordinary General Public License.  We use\r
+this license for certain libraries in order to permit linking those\r
+libraries into non-free programs.\r
+\r
+  When a program is linked with a library, whether statically or using\r
+a shared library, the combination of the two is legally speaking a\r
+combined work, a derivative of the original library.  The ordinary\r
+General Public License therefore permits such linking only if the\r
+entire combination fits its criteria of freedom.  The Lesser General\r
+Public License permits more lax criteria for linking other code with\r
+the library.\r
+\r
+  We call this license the "Lesser" General Public License because it\r
+does Less to protect the user's freedom than the ordinary General\r
+Public License.  It also provides other free software developers Less\r
+of an advantage over competing non-free programs.  These disadvantages\r
+are the reason we use the ordinary General Public License for many\r
+libraries.  However, the Lesser license provides advantages in certain\r
+special circumstances.\r
+\r
+  For example, on rare occasions, there may be a special need to\r
+encourage the widest possible use of a certain library, so that it becomes\r
+a de-facto standard.  To achieve this, non-free programs must be\r
+allowed to use the library.  A more frequent case is that a free\r
+library does the same job as widely used non-free libraries.  In this\r
+case, there is little to gain by limiting the free library to free\r
+software only, so we use the Lesser General Public License.\r
+\r
+  In other cases, permission to use a particular library in non-free\r
+programs enables a greater number of people to use a large body of\r
+free software.  For example, permission to use the GNU C Library in\r
+non-free programs enables many more people to use the whole GNU\r
+operating system, as well as its variant, the GNU/Linux operating\r
+system.\r
+\r
+  Although the Lesser General Public License is Less protective of the\r
+users' freedom, it does ensure that the user of a program that is\r
+linked with the Library has the freedom and the wherewithal to run\r
+that program using a modified version of the Library.\r
+\r
+  The precise terms and conditions for copying, distribution and\r
+modification follow.  Pay close attention to the difference between a\r
+"work based on the library" and a "work that uses the library".  The\r
+former contains code derived from the library, whereas the latter must\r
+be combined with the library in order to run.\r
+\r
+                 GNU LESSER GENERAL PUBLIC LICENSE\r
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\r
+\r
+  0. This License Agreement applies to any software library or other\r
+program which contains a notice placed by the copyright holder or\r
+other authorized party saying it may be distributed under the terms of\r
+this Lesser General Public License (also called "this License").\r
+Each licensee is addressed as "you".\r
+\r
+  A "library" means a collection of software functions and/or data\r
+prepared so as to be conveniently linked with application programs\r
+(which use some of those functions and data) to form executables.\r
+\r
+  The "Library", below, refers to any such software library or work\r
+which has been distributed under these terms.  A "work based on the\r
+Library" means either the Library or any derivative work under\r
+copyright law: that is to say, a work containing the Library or a\r
+portion of it, either verbatim or with modifications and/or translated\r
+straightforwardly into another language.  (Hereinafter, translation is\r
+included without limitation in the term "modification".)\r
+\r
+  "Source code" for a work means the preferred form of the work for\r
+making modifications to it.  For a library, complete source code means\r
+all the source code for all modules it contains, plus any associated\r
+interface definition files, plus the scripts used to control compilation\r
+and installation of the library.\r
+\r
+  Activities other than copying, distribution and modification are not\r
+covered by this License; they are outside its scope.  The act of\r
+running a program using the Library is not restricted, and output from\r
+such a program is covered only if its contents constitute a work based\r
+on the Library (independent of the use of the Library in a tool for\r
+writing it).  Whether that is true depends on what the Library does\r
+and what the program that uses the Library does.\r
+  \r
+  1. You may copy and distribute verbatim copies of the Library's\r
+complete source code as you receive it, in any medium, provided that\r
+you conspicuously and appropriately publish on each copy an\r
+appropriate copyright notice and disclaimer of warranty; keep intact\r
+all the notices that refer to this License and to the absence of any\r
+warranty; and distribute a copy of this License along with the\r
+Library.\r
+\r
+  You may charge a fee for the physical act of transferring a copy,\r
+and you may at your option offer warranty protection in exchange for a\r
+fee.\r
+\r
+  2. You may modify your copy or copies of the Library or any portion\r
+of it, thus forming a work based on the Library, and copy and\r
+distribute such modifications or work under the terms of Section 1\r
+above, provided that you also meet all of these conditions:\r
+\r
+    a) The modified work must itself be a software library.\r
+\r
+    b) You must cause the files modified to carry prominent notices\r
+    stating that you changed the files and the date of any change.\r
+\r
+    c) You must cause the whole of the work to be licensed at no\r
+    charge to all third parties under the terms of this License.\r
+\r
+    d) If a facility in the modified Library refers to a function or a\r
+    table of data to be supplied by an application program that uses\r
+    the facility, other than as an argument passed when the facility\r
+    is invoked, then you must make a good faith effort to ensure that,\r
+    in the event an application does not supply such function or\r
+    table, the facility still operates, and performs whatever part of\r
+    its purpose remains meaningful.\r
+\r
+    (For example, a function in a library to compute square roots has\r
+    a purpose that is entirely well-defined independent of the\r
+    application.  Therefore, Subsection 2d requires that any\r
+    application-supplied function or table used by this function must\r
+    be optional: if the application does not supply it, the square\r
+    root function must still compute square roots.)\r
+\r
+These requirements apply to the modified work as a whole.  If\r
+identifiable sections of that work are not derived from the Library,\r
+and can be reasonably considered independent and separate works in\r
+themselves, then this License, and its terms, do not apply to those\r
+sections when you distribute them as separate works.  But when you\r
+distribute the same sections as part of a whole which is a work based\r
+on the Library, the distribution of the whole must be on the terms of\r
+this License, whose permissions for other licensees extend to the\r
+entire whole, and thus to each and every part regardless of who wrote\r
+it.\r
+\r
+Thus, it is not the intent of this section to claim rights or contest\r
+your rights to work written entirely by you; rather, the intent is to\r
+exercise the right to control the distribution of derivative or\r
+collective works based on the Library.\r
+\r
+In addition, mere aggregation of another work not based on the Library\r
+with the Library (or with a work based on the Library) on a volume of\r
+a storage or distribution medium does not bring the other work under\r
+the scope of this License.\r
+\r
+  3. You may opt to apply the terms of the ordinary GNU General Public\r
+License instead of this License to a given copy of the Library.  To do\r
+this, you must alter all the notices that refer to this License, so\r
+that they refer to the ordinary GNU General Public License, version 2,\r
+instead of to this License.  (If a newer version than version 2 of the\r
+ordinary GNU General Public License has appeared, then you can specify\r
+that version instead if you wish.)  Do not make any other change in\r
+these notices.\r
+\r
+  Once this change is made in a given copy, it is irreversible for\r
+that copy, so the ordinary GNU General Public License applies to all\r
+subsequent copies and derivative works made from that copy.\r
+\r
+  This option is useful when you wish to copy part of the code of\r
+the Library into a program that is not a library.\r
+\r
+  4. You may copy and distribute the Library (or a portion or\r
+derivative of it, under Section 2) in object code or executable form\r
+under the terms of Sections 1 and 2 above provided that you accompany\r
+it with the complete corresponding machine-readable source code, which\r
+must be distributed under the terms of Sections 1 and 2 above on a\r
+medium customarily used for software interchange.\r
+\r
+  If distribution of object code is made by offering access to copy\r
+from a designated place, then offering equivalent access to copy the\r
+source code from the same place satisfies the requirement to\r
+distribute the source code, even though third parties are not\r
+compelled to copy the source along with the object code.\r
+\r
+  5. A program that contains no derivative of any portion of the\r
+Library, but is designed to work with the Library by being compiled or\r
+linked with it, is called a "work that uses the Library".  Such a\r
+work, in isolation, is not a derivative work of the Library, and\r
+therefore falls outside the scope of this License.\r
+\r
+  However, linking a "work that uses the Library" with the Library\r
+creates an executable that is a derivative of the Library (because it\r
+contains portions of the Library), rather than a "work that uses the\r
+library".  The executable is therefore covered by this License.\r
+Section 6 states terms for distribution of such executables.\r
+\r
+  When a "work that uses the Library" uses material from a header file\r
+that is part of the Library, the object code for the work may be a\r
+derivative work of the Library even though the source code is not.\r
+Whether this is true is especially significant if the work can be\r
+linked without the Library, or if the work is itself a library.  The\r
+threshold for this to be true is not precisely defined by law.\r
+\r
+  If such an object file uses only numerical parameters, data\r
+structure layouts and accessors, and small macros and small inline\r
+functions (ten lines or less in length), then the use of the object\r
+file is unrestricted, regardless of whether it is legally a derivative\r
+work.  (Executables containing this object code plus portions of the\r
+Library will still fall under Section 6.)\r
+\r
+  Otherwise, if the work is a derivative of the Library, you may\r
+distribute the object code for the work under the terms of Section 6.\r
+Any executables containing that work also fall under Section 6,\r
+whether or not they are linked directly with the Library itself.\r
+\r
+  6. As an exception to the Sections above, you may also combine or\r
+link a "work that uses the Library" with the Library to produce a\r
+work containing portions of the Library, and distribute that work\r
+under terms of your choice, provided that the terms permit\r
+modification of the work for the customer's own use and reverse\r
+engineering for debugging such modifications.\r
+\r
+  You must give prominent notice with each copy of the work that the\r
+Library is used in it and that the Library and its use are covered by\r
+this License.  You must supply a copy of this License.  If the work\r
+during execution displays copyright notices, you must include the\r
+copyright notice for the Library among them, as well as a reference\r
+directing the user to the copy of this License.  Also, you must do one\r
+of these things:\r
+\r
+    a) Accompany the work with the complete corresponding\r
+    machine-readable source code for the Library including whatever\r
+    changes were used in the work (which must be distributed under\r
+    Sections 1 and 2 above); and, if the work is an executable linked\r
+    with the Library, with the complete machine-readable "work that\r
+    uses the Library", as object code and/or source code, so that the\r
+    user can modify the Library and then relink to produce a modified\r
+    executable containing the modified Library.  (It is understood\r
+    that the user who changes the contents of definitions files in the\r
+    Library will not necessarily be able to recompile the application\r
+    to use the modified definitions.)\r
+\r
+    b) Use a suitable shared library mechanism for linking with the\r
+    Library.  A suitable mechanism is one that (1) uses at run time a\r
+    copy of the library already present on the user's computer system,\r
+    rather than copying library functions into the executable, and (2)\r
+    will operate properly with a modified version of the library, if\r
+    the user installs one, as long as the modified version is\r
+    interface-compatible with the version that the work was made with.\r
+\r
+    c) Accompany the work with a written offer, valid for at\r
+    least three years, to give the same user the materials\r
+    specified in Subsection 6a, above, for a charge no more\r
+    than the cost of performing this distribution.\r
+\r
+    d) If distribution of the work is made by offering access to copy\r
+    from a designated place, offer equivalent access to copy the above\r
+    specified materials from the same place.\r
+\r
+    e) Verify that the user has already received a copy of these\r
+    materials or that you have already sent this user a copy.\r
+\r
+  For an executable, the required form of the "work that uses the\r
+Library" must include any data and utility programs needed for\r
+reproducing the executable from it.  However, as a special exception,\r
+the materials to be distributed need not include anything that is\r
+normally distributed (in either source or binary form) with the major\r
+components (compiler, kernel, and so on) of the operating system on\r
+which the executable runs, unless that component itself accompanies\r
+the executable.\r
+\r
+  It may happen that this requirement contradicts the license\r
+restrictions of other proprietary libraries that do not normally\r
+accompany the operating system.  Such a contradiction means you cannot\r
+use both them and the Library together in an executable that you\r
+distribute.\r
+\r
+  7. You may place library facilities that are a work based on the\r
+Library side-by-side in a single library together with other library\r
+facilities not covered by this License, and distribute such a combined\r
+library, provided that the separate distribution of the work based on\r
+the Library and of the other library facilities is otherwise\r
+permitted, and provided that you do these two things:\r
+\r
+    a) Accompany the combined library with a copy of the same work\r
+    based on the Library, uncombined with any other library\r
+    facilities.  This must be distributed under the terms of the\r
+    Sections above.\r
+\r
+    b) Give prominent notice with the combined library of the fact\r
+    that part of it is a work based on the Library, and explaining\r
+    where to find the accompanying uncombined form of the same work.\r
+\r
+  8. You may not copy, modify, sublicense, link with, or distribute\r
+the Library except as expressly provided under this License.  Any\r
+attempt otherwise to copy, modify, sublicense, link with, or\r
+distribute the Library is void, and will automatically terminate your\r
+rights under this License.  However, parties who have received copies,\r
+or rights, from you under this License will not have their licenses\r
+terminated so long as such parties remain in full compliance.\r
+\r
+  9. You are not required to accept this License, since you have not\r
+signed it.  However, nothing else grants you permission to modify or\r
+distribute the Library or its derivative works.  These actions are\r
+prohibited by law if you do not accept this License.  Therefore, by\r
+modifying or distributing the Library (or any work based on the\r
+Library), you indicate your acceptance of this License to do so, and\r
+all its terms and conditions for copying, distributing or modifying\r
+the Library or works based on it.\r
+\r
+  10. Each time you redistribute the Library (or any work based on the\r
+Library), the recipient automatically receives a license from the\r
+original licensor to copy, distribute, link with or modify the Library\r
+subject to these terms and conditions.  You may not impose any further\r
+restrictions on the recipients' exercise of the rights granted herein.\r
+You are not responsible for enforcing compliance by third parties with\r
+this License.\r
+\r
+  11. If, as a consequence of a court judgment or allegation of patent\r
+infringement or for any other reason (not limited to patent issues),\r
+conditions are imposed on you (whether by court order, agreement or\r
+otherwise) that contradict the conditions of this License, they do not\r
+excuse you from the conditions of this License.  If you cannot\r
+distribute so as to satisfy simultaneously your obligations under this\r
+License and any other pertinent obligations, then as a consequence you\r
+may not distribute the Library at all.  For example, if a patent\r
+license would not permit royalty-free redistribution of the Library by\r
+all those who receive copies directly or indirectly through you, then\r
+the only way you could satisfy both it and this License would be to\r
+refrain entirely from distribution of the Library.\r
+\r
+If any portion of this section is held invalid or unenforceable under any\r
+particular circumstance, the balance of the section is intended to apply,\r
+and the section as a whole is intended to apply in other circumstances.\r
+\r
+It is not the purpose of this section to induce you to infringe any\r
+patents or other property right claims or to contest validity of any\r
+such claims; this section has the sole purpose of protecting the\r
+integrity of the free software distribution system which is\r
+implemented by public license practices.  Many people have made\r
+generous contributions to the wide range of software distributed\r
+through that system in reliance on consistent application of that\r
+system; it is up to the author/donor to decide if he or she is willing\r
+to distribute software through any other system and a licensee cannot\r
+impose that choice.\r
+\r
+This section is intended to make thoroughly clear what is believed to\r
+be a consequence of the rest of this License.\r
+\r
+  12. If the distribution and/or use of the Library is restricted in\r
+certain countries either by patents or by copyrighted interfaces, the\r
+original copyright holder who places the Library under this License may add\r
+an explicit geographical distribution limitation excluding those countries,\r
+so that distribution is permitted only in or among countries not thus\r
+excluded.  In such case, this License incorporates the limitation as if\r
+written in the body of this License.\r
+\r
+  13. The Free Software Foundation may publish revised and/or new\r
+versions of the Lesser General Public License from time to time.\r
+Such new versions will be similar in spirit to the present version,\r
+but may differ in detail to address new problems or concerns.\r
+\r
+Each version is given a distinguishing version number.  If the Library\r
+specifies a version number of this License which applies to it and\r
+"any later version", you have the option of following the terms and\r
+conditions either of that version or of any later version published by\r
+the Free Software Foundation.  If the Library does not specify a\r
+license version number, you may choose any version ever published by\r
+the Free Software Foundation.\r
+\r
+  14. If you wish to incorporate parts of the Library into other free\r
+programs whose distribution conditions are incompatible with these,\r
+write to the author to ask for permission.  For software which is\r
+copyrighted by the Free Software Foundation, write to the Free\r
+Software Foundation; we sometimes make exceptions for this.  Our\r
+decision will be guided by the two goals of preserving the free status\r
+of all derivatives of our free software and of promoting the sharing\r
+and reuse of software generally.\r
+\r
+                           NO WARRANTY\r
+\r
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO\r
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.\r
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR\r
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY\r
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE\r
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\r
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE\r
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME\r
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\r
+\r
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN\r
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY\r
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU\r
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR\r
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE\r
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING\r
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A\r
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF\r
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH\r
+DAMAGES.\r
+\r
+                    END OF TERMS AND CONDITIONS\r
+\r
+           How to Apply These Terms to Your New Libraries\r
+\r
+  If you develop a new library, and you want it to be of the greatest\r
+possible use to the public, we recommend making it free software that\r
+everyone can redistribute and change.  You can do so by permitting\r
+redistribution under these terms (or, alternatively, under the terms of the\r
+ordinary General Public License).\r
+\r
+  To apply these terms, attach the following notices to the library.  It is\r
+safest to attach them to the start of each source file to most effectively\r
+convey the exclusion of warranty; and each file should have at least the\r
+"copyright" line and a pointer to where the full notice is found.\r
+\r
+    <one line to give the library's name and a brief idea of what it does.>\r
+    Copyright (C) <year>  <name of author>\r
+\r
+    This library is free software; you can redistribute it and/or\r
+    modify it under the terms of the GNU Lesser General Public\r
+    License as published by the Free Software Foundation; either\r
+    version 2.1 of the License, or (at your option) any later version.\r
+\r
+    This library is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+    Lesser General Public License for more details.\r
+\r
+    You should have received a copy of the GNU Lesser General Public\r
+    License along with this library; if not, write to the Free Software\r
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+\r
+Also add information on how to contact you by electronic and paper mail.\r
+\r
+You should also get your employer (if you work as a programmer) or your\r
+school, if any, to sign a "copyright disclaimer" for the library, if\r
+necessary.  Here is a sample; alter the names:\r
+\r
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the\r
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.\r
+\r
+  <signature of Ty Coon>, 1 April 1990\r
+  Ty Coon, President of Vice\r
+\r
+That's all there is to it!\r
+\r
+\r
diff --git a/ekit/com/hexidec/util/Base64Codec.java b/ekit/com/hexidec/util/Base64Codec.java
new file mode 100644 (file)
index 0000000..ebf367c
--- /dev/null
@@ -0,0 +1,193 @@
+package com.hexidec.util;\r
+\r
+import java.util.Vector;\r
+\r
+public class Base64Codec\r
+{\r
+       public static Vector Base64Tokens = new Vector(64);\r
+       static\r
+       {\r
+               Base64Tokens.add("A");\r
+               Base64Tokens.add("B");\r
+               Base64Tokens.add("C");\r
+               Base64Tokens.add("D");\r
+               Base64Tokens.add("E");\r
+               Base64Tokens.add("F");\r
+               Base64Tokens.add("G");\r
+               Base64Tokens.add("H");\r
+               Base64Tokens.add("I");\r
+               Base64Tokens.add("J");\r
+               Base64Tokens.add("K");\r
+               Base64Tokens.add("L");\r
+               Base64Tokens.add("M");\r
+               Base64Tokens.add("N");\r
+               Base64Tokens.add("O");\r
+               Base64Tokens.add("P");\r
+               Base64Tokens.add("Q");\r
+               Base64Tokens.add("R");\r
+               Base64Tokens.add("S");\r
+               Base64Tokens.add("T");\r
+               Base64Tokens.add("U");\r
+               Base64Tokens.add("V");\r
+               Base64Tokens.add("W");\r
+               Base64Tokens.add("X");\r
+               Base64Tokens.add("Y");\r
+               Base64Tokens.add("Z");\r
+               Base64Tokens.add("a");\r
+               Base64Tokens.add("b");\r
+               Base64Tokens.add("c");\r
+               Base64Tokens.add("d");\r
+               Base64Tokens.add("e");\r
+               Base64Tokens.add("f");\r
+               Base64Tokens.add("g");\r
+               Base64Tokens.add("h");\r
+               Base64Tokens.add("i");\r
+               Base64Tokens.add("j");\r
+               Base64Tokens.add("k");\r
+               Base64Tokens.add("l");\r
+               Base64Tokens.add("m");\r
+               Base64Tokens.add("n");\r
+               Base64Tokens.add("o");\r
+               Base64Tokens.add("p");\r
+               Base64Tokens.add("q");\r
+               Base64Tokens.add("r");\r
+               Base64Tokens.add("s");\r
+               Base64Tokens.add("t");\r
+               Base64Tokens.add("u");\r
+               Base64Tokens.add("v");\r
+               Base64Tokens.add("w");\r
+               Base64Tokens.add("x");\r
+               Base64Tokens.add("y");\r
+               Base64Tokens.add("z");\r
+               Base64Tokens.add("0");\r
+               Base64Tokens.add("1");\r
+               Base64Tokens.add("2");\r
+               Base64Tokens.add("3");\r
+               Base64Tokens.add("4");\r
+               Base64Tokens.add("5");\r
+               Base64Tokens.add("6");\r
+               Base64Tokens.add("7");\r
+               Base64Tokens.add("8");\r
+               Base64Tokens.add("9");\r
+               Base64Tokens.add("+");\r
+               Base64Tokens.add("/");\r
+       }       \r
+       public static final char Base64Pad = '=';\r
+       public static final char Linefeed = (char)10;\r
+       public static final char Carriage = (char)13;\r
+       public static final int  LineMax = 75;\r
+\r
+       public Base64Codec()\r
+       {\r
+       }\r
+\r
+       public static String encode(String source)\r
+       {\r
+               byte[] sourceBytes = source.getBytes();\r
+               int byteTriad = sourceBytes.length % 3;\r
+               StringBuffer encoding = new StringBuffer();\r
+               int bitOffset = 7;\r
+               int b64Offset = 5;\r
+               int bytePlace = 0;\r
+               byte tokenValue = (byte)0;\r
+               int lineLength = 0;\r
+               while(bytePlace < sourceBytes.length)\r
+               {\r
+                       tokenValue = (byte)((byte)tokenValue | (byte)((sourceBytes[bytePlace] & (1 << bitOffset)) > 0 ? (1 << b64Offset) : (byte)0));\r
+                       bitOffset--;\r
+                       if(bitOffset < 0)\r
+                       {\r
+                               bitOffset = 7;\r
+                               bytePlace++;\r
+                       }\r
+                       b64Offset--;\r
+                       if(b64Offset < 0)\r
+                       {\r
+                               b64Offset = 5;\r
+                               encoding.append((String)(Base64Tokens.elementAt(tokenValue)));\r
+                               tokenValue = (byte)0;\r
+                               lineLength++;\r
+                               if(lineLength > LineMax)\r
+                               {\r
+                                       encoding.append(Carriage);\r
+                                       encoding.append(Linefeed);\r
+                                       lineLength = 0;\r
+                               }\r
+                       }\r
+               }\r
+               if(b64Offset != 5)\r
+               {\r
+                       bytePlace--;\r
+                       for(int i = b64Offset; i >= 0; i--)\r
+                       {\r
+                               if(bitOffset >= 0)\r
+                               {\r
+                                       tokenValue = (byte)((byte)tokenValue | (byte)((sourceBytes[bytePlace] & (1 << bitOffset)) > 0 ? (1 << i) : (byte)0));\r
+                               }\r
+                               bitOffset--;\r
+                       }\r
+                       encoding.append((String)(Base64Tokens.elementAt(tokenValue)));\r
+               }       \r
+               if(byteTriad == 2)\r
+               {\r
+                       encoding.append(Base64Pad);\r
+               }\r
+               else if(byteTriad == 1)\r
+               {\r
+                       encoding.append(Base64Pad);\r
+                       encoding.append(Base64Pad);\r
+               }\r
+               return encoding.toString();\r
+       }\r
+\r
+       public static String decode(String source)\r
+       {\r
+               StringBuffer decoding = new StringBuffer();\r
+               int bitOffset = 7;\r
+               int b64Offset = 5;\r
+               int bytePlace = 0;\r
+               byte charValue = (byte)0;\r
+               while(bytePlace < source.length())\r
+               {\r
+                       if(source.charAt(bytePlace) == Base64Pad)\r
+                       {\r
+                               // end processing when encountering special end-padding character\r
+                               break;\r
+                       }\r
+                       if(source.charAt(bytePlace) == Linefeed || source.charAt(bytePlace) == Carriage)\r
+                       {\r
+                               // ignore standard line break characters\r
+                               bytePlace++;\r
+                               continue;\r
+                       }\r
+                       else\r
+                       {\r
+                               if(!Base64Tokens.contains(source.substring(bytePlace, bytePlace + 1)))\r
+                               {\r
+                                       // ignore unknown characters (mostly implemented to deal with other line break character sequences)\r
+                                       bytePlace++;\r
+                                       continue;\r
+                               }\r
+                               else\r
+                               {\r
+                                       byte currentByte = (byte)(Base64Tokens.indexOf(source.substring(bytePlace, bytePlace + 1)));\r
+                                       charValue = (byte)((byte)charValue | (byte)((currentByte & (1 << b64Offset)) > 0 ? (1 << bitOffset) : (byte)0));\r
+                                       bitOffset--;\r
+                                       if(bitOffset < 0)\r
+                                       {\r
+                                               bitOffset = 7;\r
+                                               decoding.append((char)charValue);\r
+                                               charValue = (byte)0;\r
+                                       }\r
+                                       b64Offset--;\r
+                                       if(b64Offset < 0)\r
+                                       {\r
+                                               b64Offset = 5;\r
+                                               bytePlace++;\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+               return decoding.toString();\r
+       }\r
+}
\ No newline at end of file
diff --git a/ekit/com/hexidec/util/CMUS.proposal.txt b/ekit/com/hexidec/util/CMUS.proposal.txt
new file mode 100644 (file)
index 0000000..c03b0ae
--- /dev/null
@@ -0,0 +1 @@
+Common MUsical Score\r\r/* ========================================================================= *\r                         CMUS - Common Musical Score\r\r                     An IFF File format for interchanging\r                   musical data using Common Music Notation\r\r                            by Talin (David Joiner)\r\r                                  Verion 0.4\r * ========================================================================= */\r\r#ifndef CMUS_H\r#define CMUS_H\r\r/* ========================================================================= *\r    Note to Non-Amiga users of this document\r    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r        CMUS is an IFF (Interchange File Format) file. IFF is a "Meta-standard"\r    for making extensible, self-identifying file formats, and was developed\r    by Commodore and Electronic Arts. In order to understand CMUS you will\r    need to get the IFF Documentation. The quickest way to do this is to\r    get the "Amiga ROM Kernal Manual: Devices" volume and look in the Appendix.\r * ========================================================================= *\r    Note on Timing:\r    ~~~~~~~~~~~~~~~\r        Common Music Notation is a symbolic, rather than a literal\r    representation. It is supposed to be interpreted by the player. A note\r    which is listed as "A quarter note", will seldom be played at the exact\r    time or duration as written. These deviations from mathematically perfect\r    time are important; they are part of what musicians call "feel" or\r    "liveliness".\r        Accordingly, FORM CMUS has two different kinds of timing information.\r    _Formal Time_ is represented in symbolic form: Each symbol has a field\r    which indicates it's duration (dotted quarter-note, etc) in symbolic units.\r    The formal start time of an event can be obtained by summing the durations\r    of all the previous times in the measure.\r        In addition, there is also _Casual Time_. Each event has a "start time"\r    which is the number of basic clock units from the start of the measure to\r    the start of that event. Some event types also have "duration" fields of\r    a similar nature.\r        In general, although there will probably be a strong correlation\r    between formal time and casual time, there is no guarantee of this.\r    Certainly this FORM does not enforce any relationship between the two.\r    This means that you cannot, in general, derive one from the other. You can\r    at most make an educated guess, and even that is a non-trivial problem\r    from an algorithmic point of view.\r\r * ========================================================================= *\r    Note on Layout Measurements:\r    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r        In general, I have tried to make all measurements as "device-\r    independent" as possible.\r\r        Measurements of page dimensions and other page-related information\r    such as margins and indentations are represented in micrometers.\r        Converting from micrometers to inches and "big points" (the definition\r    of points used by Adobe and Apple) can be done with the following\r    formulas:\r\r        inches = micrometers / 25400;\r\r        points = micrometers * 72 / 25400;\r\r        Vertical distances of musical items are all measured in "Levels".\r    A level is one half the distance between the lines of a staff. A note on\r    the centerline of the staff is at level zero. Placing the note just above\r    that line (between the 2nd and 3rd staff line) makes it level 1, while\r    placing it below the centerline makes it level -1. Note that up is positive\r    in this coordinate system.\r        Note positions are recorded as a fraction of the measure width.\r\r * ========================================================================= *\r    Rules for clipboard use:\r    ~~~~~~~~~~~~~~~~~~~~~~~~\r        A CMUS chunk may be copied to the clipboard. In such cases, it is\r    possible that only a subset of the data might be written. Specifically,\r    measures and signatures which occur before the first selection point,\r    or after the last selection point should not be included. Note that\r    the measure containing the first selection point should be written,\r    however, even if it is not in the selection range itself. (As to whether\r    measure-lines are selectable is up to the application). In addition,\r    an initial time signature item for that measure should be written as\r    well; key signature and clef items are optional in this case. The\r    application receiving the clip has the option of whether to use the\r    signature items in the clip, or to ignore them and use the existing\r    signatures in the score. The application can also decide to "insert"\r    the clip into the score (causing existing other events to be shifted\r    later in time), or "merging" the events with the existing items.\r    The application can also choose to respect measure lines in the clip\r    (each new measure line causes the notes to be pasted into the next\r    measure) or to "flow" the notes across measure boundaries.\r        Note that the notes in a clip may be non-contiguous. For example,\r    If the user were to select every second note and copy those to the\r    clipboard, there would be "gaps" in the clipped track. Unfortunately,\r    a reader program would not be able to detect those gaps (since formal\r    time does not have an explicit start time) and thus the formal time\r    and the casual time would get out of sync. To avoid this problem,\r    "filler" events can be inserted into the score to fill up the empty space.\r    Note that the duration of a filler event is formal, unlike all the\r    other events.\r        Notation programs which only support contiguous selection (i.e.\r    can't have a deselected note between two selected notes) can ignore\r    filler items.\r        A filler event at the end of the measure is not neccessary.\r    In fact, there is no requirement in CMUS that a measure be "filled".\r    In addition, certain music programs allow more notes in a measure than\r    would legally fit (only while editing, the extra notes are never played).\r    CMUS readers should handle this case robustly.\r\r        This allows a reader to make intelligent use of the clip. The clip\r    can be pasted relative to an insertion point, and the relationship of\r    notes to measures can be (optionally) preserved, even if the selection\r    was non-contiguous.\r * ========================================================================= *\r    Future Directions\r    ~~~~~~~~~~~~~~~~~\r        A number of musical features are currently mising from the CMUS spec,\r    such as the ability for a track to jump from one staff to another. In\r    addition, there are a number of features which would be desirable on the\r    "page" level, such as seperate margins for each page (currently, there is\r    no representation of individual pages in the spec).\r        All of these things can easily be added by defining new IFF chunks\r    or new event types. I have not done this because I feel that these\r    additional features would best be designed by the person who needs them,\r    in other words someone designing a music product that requires such\r    features and is familiar with the issues inolved. Otherwise, the format\r    might be defined wrongly, missing subtle advantages which\r*/\r\r/* ========================================================================= *\r                             General Definitions\r * ========================================================================= */\r\rtypedef long            Micrometers;\r\r#if CM_MICRO_CONVERSION\r\r    /* (optional) conversion to / from inches */\r\r#define InchesToMicros(inches)  ((inches) * 25400)\r#define MicrosToInches(micros)  (((micros) + 12700) / 25400)\r\r#define HundredthsToMicros(inches)  ((inches) * 254)\r#define MicrosToHundredths(micros)  (((micros) + 127) / 254)\r\r#define PointsToMicros(points)  (((points) * 25400 + 36) / 72)\r#define MicrosToPoints(micros)  (((micros) * 72 + 12700) / 25400)\r\r#endif\r\r/* ========================================================================= *\r                           Score Header Chunk (SCHD)\r * ========================================================================= */\r\rtypedef struct {\r    WORD                scBarsPerLine;      /* preferred bars per line      */\r    WORD                scOverallVolume;    /* overall volume of score      */\r\r    Micrometers         scPageWidth,        /* width of page                */\r                        scPageHeight,       /* height of page               */\r                        scTopMargin,        /* top margin of score on page 1*/\r                        scFirstLineIndent,  /* left margin indent on line 1 */\r                        scLineIndent;       /* left indent on other lines   */\r} CM_ScoreHeader;\r\r/* ========================================================================= *\r                            Staff Table Chunk (STAF)\r\r   This section describes the data structures which are used in the CMUS 'STAF'\r   Chunk. There is one STFF chunk per score, which contains an array of\r   StaffEntry structres (1 per staff in the document).\r\r * ========================================================================= */\r\rtypedef struct {\r    WORD                staffFlags;         /* various flags                */\r\r        /*  This defines the vertical size of a measure. Both of the distances\r            are measured from the center line of the staff (in fact all staff-\r            relative distances are represented this way).\r        */\r\r    Micrometers         staffSpaceAbove,    /* space above staff            */\r                        staffSpaceBelow;    /* space below staff            */\r\r    Micrometers         staffLevelSize;     /* distance between staff lines */\r\r} CM_StaffEntry;\r\r    /* This flag indicates that a formfeed should be done before printing\r        this staff (used when a score has more staffs than will fit on a page.\r    */\r\r#define STAFF_PAGEBREAK (1<<0)\r\r    /*  This indicates that the measure lines for this staff should not be\r        connected to the measure lines for the staff below\r    */\r\r#define STAFF_BAR_BROKEN (1<<1)\r\r    /*  This flag indicates that a set of "curly braces" should connect this\r        staff with the staff below.\r    */\r\r#define STAFF_BRACED    (1<<2)              /* Staff is "braced" with next  */\r\r    /*  These flags indicate the start and end of a square bracket which can\r        span over several staffs. The brace should start at the staff\r        marked with the "START" bit and continue until a staff with the\r        "END" bit is encountered.\r    */\r\r#define STAFF_BRACKET_START (1<<3)\r#define STAFF_BRACKET_END   (1<<4)\r\r/* ========================================================================= *\r                               Track Chunk (TRCK)\r\r   This section describes the data structures which are used in the CMUS 'TRCK'\r   Chunk.\r\r   A track is a sequence of notes which reside on a staff. In the simplest\r   case, there is one TRCK chunk per melody line in the score. However, a\r   track can contain chords, rests, etc, as well.\r\r   A more precise definition of a track is that a track is a sequence of\r   chords, where all the notes within each chord have the same start time\r   and the same duration (in formal time of course; in casual time anything\r   is possible). Note that ties can be used to create the illusion of\r   having broken this rule.\r\r * ========================================================================= */\r\r/*  Track Header structure:\r\r    Each track begins with a track header structure, followed by any number\r    of score items. (Use the chunk length to determine when to stop reading\r    score items).\r*/\r\rtypedef struct {\r    UWORD               trkStaff,           /* staff number to place this on*/\r                        trkTrack,           /* track number within staff    */\r                        trkFlags;           /* flags for staff header       */\r\r        /*  Sometimes notes on the staff are written transposed from how they\r            should actually be played. This is the number that should be added\r            to the pitch before it is actually played back.\r        */\r\r    WORD                trkTransposition;   /* playback transposition       */\r\r} CM_TrackHeader;\r\r/* ========================================================================= *\r                                      Track Item\r * ========================================================================= */\r\r/*  Item Header:\r\r    Score items are variable in length. The first byte of the item is the\r    length of the item in WORDS. This will allow new item types to be added\r    in the future. All score items are an integer number of WORDS long.\r\r    Each score item has a standard header structure, followed by a variable\r    amount of item-specific data. The 'itemType' field is used to determine what\r    that data is.\r\r    'itemLength' is the length of the item in WORDS. This allows items to be\r    from 2 to 512 bytes long. (The value '0' is reserved as a special case).\r\r    'itemXPos' contains the X position of the item in fractions of the measure's\r    width. Note that the area containing the signatures, and the area just\r    before the ending measure line are not considered part of this range.\r    Think of it this way: The value 0 is the first possible note position.\r    The value 0x7fff if the last possible note position. Items placed at\r    these positions should not run into the graphics at either the beginning\r    or the end of the measure. In addition, negative numbers are also\r    allows, which is used for symbols which penetrate into the "signature"\r    area. In this case, 0 represents the first possible note position, and\r    -0x8000 represents the actual barline. This convention is normally only\r    used for lyrics, which can intrude into the signature area.\r\r    'itemStart' is used to represent the real starting time of each event.\r    This is recorded as a delta-time, in other words itemStart contains\r    how many clock ticks have elapsed between the current item and the item\r    before it. Note that because of the fact that events can sometimes occur\r    out of order (for example, notes in a chord can be ordered by pitch rather\r    than by time, and they might not all start at exactly the same clock),\r    this value can be negative.\r        In addition, the clock is reset at each measure boundary. In other\r    words, the length of a measure is determined only by it's time signature,\r    and not by the delta between the last note and the next measure line.\r    In fact, the itemStart field for measure line items is ignored and should\r    always be set to zero.\r        An item's start time does NOT have to exactly match the event's\r    "formal" time. For example, an event at the beginning of a measure does\r    not have to start at exactly time zero, but can be offset somewhat.\r    This allows the subtle nuances of a live performance to be preserved, if\r    the notation software allows for that capability.\r\r    The 'itemStart' field (and the noteDuration field defined later) use a\r    clock standard of 960 clock ticks per whole note. Thus, a quarter note\r    is one/quarter that, or 240. This number is divisible by 3, 5, and several\r    powers of two, making it convenient for representing triplets and\r    quintuplets as well as small note values.\r*/\r\rtypedef struct {\r    UBYTE               itemLength,         /* length of item in WORDS      */\r                        itemType;           /* type of item                 */\r    WORD                itemXPos;           /* horizontal position of item  */\r    WORD                itemStart;          /* start time, in ticks         */\r} CM_ItemHeader;\r\r#define WHOLE_NOTE_DURATION     960         /* duration of a whole note     */\r\r#define MAX_ITEM_XPOS   0x7fff\r#define MMIN_ITEM_XPOS  -0x8000\r\r    /* type codes for chunk item types */\r\renum notation_item_types {\r    MEASURE_ITEM = 0,                       /* measure line                 */\r    SIGNATURE_ITEM,                         /* time sig., key sig., or clef */\r    NOTE_ITEM,                              /* first note in a chord        */\r    CHORD_ITEM,                             /* additional notes in a chord  */\r    FILLER_ITEM,                            /* fills up empty gaps          */\r    DYNAMIC_ITEM,                           /* dynamic volume item (fff)    */\r    INSTRUMENT_ITEM,                        /* instrument change item       */\r    TEMPO_ITEM,                             /* tempo change item            */\r    REPEAT_ITEM,                            /* for jumping around in score  */\r    BEGIN_GROUP_ITEM,                       /* begin slur, crescendo, etc.  */\r    END_GROUP_ITEM,                         /* end slur, crecendo, etc.     */\r    TABLATURE_ITEM,                         /* guitar or other tablature    */\r};\r\r/* ========================================================================= *\r                                  Measure Line Item\r * ========================================================================= */\r\r/*  This item represents the beginning of a new measure. As such, there should\r    be one of these at the beginning of the track, but not at the end.\r*/\r\rtypedef struct {\r    CM_ItemHeader       measureItem;        /* item header                  */\r    Micrometers         measureWidth;       /* width of measure             */\r    UBYTE               measureFlags;       /* various flags, see below     */\r\r        /*  measureEnding: If non-zero, it means that this measure is part\r            of an ending block. The value indicates which ending this measure\r            is part of. For example, if the value = 1, then this measure\r            is only played the first time through, if the value = 2 then\r            it is only played the second time through.\r\r            Each "repeat" section in the score can have it's own set of\r            endings.\r\r            "Endings" can be longer than one measure. Each measure that\r            is encountered that has the same value of measureEnding as the\r            previous measure is considered part of the same ending.\r        */\r\r    UBYTE               measureEnding;      /* "ending" this measure is in  */\r} CM_Measure;\r\r#define MEASURE_FULL_WIDTH 0x7fff           /* full width of score          */\r\renum measureFlags {\r\r        /*  Draw a double bar at the end of this measure. The reason for\r            associating the double-bar flag with the next measure line is\r            because double bar can occur at the end of the score but not\r            at the beginning.\r        */\r    MEASUREF_DOUBLE_BAR = (1<<0),\r\r        /*  This is a "line break", in other words it indicates that this\r            measure should start a new line.\r        */\r\r    MEASUREF_NEW_LINE   = (1<<1),\r\r        /*  If set, this flags means that the measure width was set by the\r            user. It not set, it means that measure width was calculated on\r            the fly, and can be re-adjusted feely if needed to line things\r            up. Note that this width includes signatures, but does not include\r            any indentation from the left margin of the document.\r        */\r\r    MEASUREF_FIXED      = (1<<2),\r\r};\r\r/* ========================================================================= *\r                               Signature Items\r * ========================================================================= */\r\r    /*  Signature items are usually placed just after the measure line.\r\r        Some notators have the ability to change clef in the middle of a\r        measure, but not all notators need support this. If it is not\r        supported, and a clef is encountered in the middle of a measure, it\r        is assumed to apply to the entire measure and therefore is associated\r        with the previous measure line.\r    */\r\r    /*  Signature types: Each signature has a "sigSubType" field which\r        indicates the type of signature. In addition, the high bit of the\r        signature type field indicates that the signature should not be\r        shown visibly.\r    */\r\renum SignatureTypes {\r    SIGTYPE_TIMESIG=1,\r    SIGTYPE_CLEF,\r    SIGTYPE_MAJORKEY,\r    SIGTYPE_MINORKEY,\r\r    SIGTYPE_HIDDEN=(1<<7)\r};\r\r    /*  Stores a time signature. 'Beats' is the number above the line, and\r        'Notes' is the number below the line. For example, '3/4' time is\r        stored as beats = 3, notes = 4.\r\r        "Common Time" (The "C" symbol) which is equivalent to 4/4 is stored\r        as 4/0 (beats = 4, notes = 0).\r\r        "Cut Time" ("C" with a slash through it) which is equivalent to\r        2/4 is stored as 2/0 (beats = 2, notes = 0).\r\r        In other words, the value "0" in "sigNotes" should always be treated\r        as the value "4" when calculating measure lengths. See the\r        MEASURE_LENGTH macro for an example of this.\r    */\r\rtypedef struct {\r    CM_ItemHeader       sigItem;            /* item header                  */\r    UBYTE               sigSubType,         /* (= SIGTYPE_TIMESIG)          */\r                        sigBeats,           /* beats per bar                */\r                        sigNotes,           /* size of each beat            */\r                        sigPad;\r} CM_TimeSignature;\r\r    /* compute the measure length in clock ticks */\r\r#define MEASURE_LENGTH(beats, notes) \\r    (WHOLE_NOTE_DURATION * beats / (notes ? notes : 4))\r\r    /* stores a Clef */\r\rtypedef struct {\r    CM_ItemHeader       sigItem;            /* item header                  */\r    UBYTE               sigSubType;         /* (= SIGTYPE_CLEF)             */\r    UBYTE               sigClef;            /* new clef                     */\r} CM_Clef;\r\r    /*  Definitions of clef types. Note clef modifier bits which are used as\r        part of this field as well.\r    */\r\renum ClefTypes {\r    TREBLE_CLEF = 0,                        /* G clef in normal position    */\r    BASS_CLEF,                              /* F clef in normal position    */\r    ALTO_CLEF,                              /* C clef centered on line 3    */\r    TENOR_CLEF,                             /* C clef centered on line 2    */\r\r        /* optional clefs, some of which are obselete (in the U.S.) */\r\r    SOPRANO_CLEF,                           /* C clef centered on line 5    */\r    MEZZO_SOPRANO_CLEF,                     /* C clef centered on line 4    */\r    BARITONE_CLEF,                          /* F clef one line lower        */\r    FRENCH_VIOLIN_CLEF,                     /* G clef one line lower        */\r\r        /*  For drum scores. One of the things implied by a drum clef is that\r            there might not be a relationship between a note's vertical\r            position and it's MIDI note number, unlike other clef types.\r            (This could be especially handy for work with MIDI drum machines).\r        */\r\r    DRUM_CLEF,                              /* vertical lines or box        */\r\r        /* clef modifier bits: A clef can be raised or lowered by one or two\r            octaves. This is notated by placing a small "8" or "15" above or\r            below the clef.\r        */\r\r    CLEF_DOWN_1_OCTAVE=(1<<4),              /* clef 1 oct lower (8 below)   */\r    CLEF_DOWN_2_OCTAVES=(1<<5),             /* clef 2 oct lower (15 below)  */\r    CLEF_UP_1_OCTAVE=(1<<6),                /* clef 1 oct higher (8 above)  */\r    CLEF_UP_2_OCTAVE=(1<<7),                /* clef 2 oct higher (15 above) */\r};\r\r    /*  stores a Key Signature. (used for both major and minor)\r\r        'sigKeySig' is a signed BYTE, where '0' is the key of C. Positive\r        numbers represent the number of sharps, so 1=G, 2=D, etc, around the\r        circle of fifths. Negative numbers represent the number of flats,\r        F=-1, B-Flat = -2, etc.\r\r        For minor keys, 0 is the key of A-minor, which like C has no sharps\r        or flats.\r\r        Other types of key signatures may be supported in the future, but\r        will probably be done as a different type of signature item.\r    */\r\rtypedef struct {\r    CM_ItemHeader       sigItem;            /* item header                  */\r    UBYTE               sigSubType;         /* (== SIGTYPE_KEYSIG)          */\r    BYTE                sigKeySig;          /* new key signature            */\r} CM_KeySignature;\r\r    /* major key definitions */\r\r#define KEY_OF_C_MAJOR           0\r#define KEY_OF_G_MAJOR           1\r#define KEY_OF_D_MAJOR           2\r#define KEY_OF_A_MAJOR           3\r#define KEY_OF_E_MAJOR           4\r#define KEY_OF_B_MAJOR           5\r#define KEY_OF_F_SHARP_MAJOR     6\r#define KEY_OF_C_SHARP_MAJOR     7\r#define KEY_OF_F_MAJOR          -1\r#define KEY_OF_B_FLAT_MAJOR     -2\r#define KEY_OF_E_FLAT_MAJOR     -3\r#define KEY_OF_A_FLAT_MAJOR     -4\r#define KEY_OF_D_FLAT_MAJOR     -5\r#define KEY_OF_G_FLAT_MAJOR     -6\r#define KEY_OF_C_FLAT_MAJOR     -7\r\r    /* minor key definitions */\r\r#define KEY_OF_A_MINOR           0\r#define KEY_OF_E_MINOR           1\r#define KEY_OF_B_MINOR           2\r#define KEY_OF_F_SHARP_MINOR     3\r#define KEY_OF_C_SHARP_MINOR     4\r#define KEY_OF_G_SHARP_MINOR     5\r#define KEY_OF_D_SHARP_MINOR     6\r#define KEY_OF_A_SHARP_MINOR     7\r#define KEY_OF_D_MINOR          -1\r#define KEY_OF_G_MINOR          -2\r#define KEY_OF_C_MINOR          -3\r#define KEY_OF_F_MINOR          -4\r#define KEY_OF_B_FLAT_MINOR     -5\r#define KEY_OF_E_FLAT_MINOR     -6\r#define KEY_OF_A_FLAT_MINOR     -7\r\r/* ========================================================================= *\r                              Note or Chord item\r * ========================================================================= */\r\r    /*  Note Items.\r\r        CHORDS: The first note of a chord is always of type "note".\r        Additional notes, or "intervals" are stored using the "chord"\r        type. The itemXPos, noteTuple, noteDots, noteDivision, noteStyle,\r        noteArpeggio, noteTrill and and noteBeamHeight fields are ignored\r        for chord items and are derived from the base note, however score\r        writers should set them to the same as the base note for consistency.\r\r        RESTS: A rest is a note item with a notePitch of 255. Rests may not\r        be chorded.\r\r        DRUM HEADS: If the NOTEF_DRUM flag is set, indicating that the\r        note has a "drum head" rather than an ordinary note head, then\r        all of the pitch-modifier fields should be ignored.\r\r        OPTIONAL FIELDS: For less sophisticated programs, many of the fields\r        in the note structure can be ignored.\r            At a minimum, notation programs should look at noteLevel,\r        noteAccidental, noteDivision and noteDots. When writing, all other\r        fields can be set to zero, with the exception of noteDuration\r        which should be set to the formal duration of the note in clock\r        ticks.\r            Sequencer programs should look at notePitch and noteDuration\r        when loading CMUS scores. Writing is more difficult. It is suggested\r        that unless the program is very sophisticated, that a different\r        FORM, or perhaps a Standard MIDI File, be used for writing out\r        sequencer data, as most of the fields in CMUS have meaning only to\r        a notator-type program.\r\r        Explanation of Fields:\r        ~~~~~~~~~~~~~~~~~~~~~~\r\r        noteDuration -- The casual duration of the note.\r\r        noteFlags -- various flags which affect either this note. Note that\r            the NOTEF_TIED and NOTEF_TIEDOWN can be different for each\r            note in a chord.\r\r        noteDots: 0, 1 or 2 depending on the number of "dots" this note\r            has. A dotted note is 50% longer. A double-dotted note is\r            75% longer.\r\r        noteDivision: Indicates the base duration of the note: whole note,\r            half note, quarter note, etc.\r\r        notePitch: The MIDI pitch number for this note.\r\r        noteArpeggio: Indicates an arpeggiated chord, one where the individual\r            notes are played sequentially (like a harp).\r\r        noteTrill: Trills are a rapid alternation between two notes. There\r            are vaious kinds, see below.\r\r        noteAccidental: This includes things like sharps and flats.\r\r        noteLevel: This is the distance, in levels, from the center line of\r            the staff.\r\r        noteBeamHeight: The height of a beamed group of notes isn't always\r            related to the height that the stem would be if the note were not\r            beamed. This field is the distance, in levels, from the center\r            line of the staff to the beam's position. This field is only\r            meaningful for the first and last note of a beam.\r\r        noteStyle: This is a field of flags which indicate things like\r            Staccato, Legato, and other "performance style" modifiers.\r    */\r\r/*  What the note structure looks like with bitfields:\r\r    CM_ItemHeader       noteItem;           -- item header\r\r    UWORD               noteDuration;       -- real duration, in ticks\r    UWORD               noteFlags;\r\r    unsigned int        Pad1           : 2\r                        noteDots       : 2, -- dotted, double-dotted\r                        noteDivision   : 4, -- quarter note, etc.\r\r    UBYTE               notePitch;          -- MIDI note number\r    unsigned int        noteArpeggio   : 2, -- arpeggiation\r                        noteTrill      : 3, -- various trill types\r                        noteAccidental : 3; -- sharp, flat, etc.\r\r    BYTE                noteLevel;          -- dist from staff centerline\r    BYTE                noteBeamHeight;     -- Y position of beam\r    UBYTE               noteStyle;          -- Note Style type\r*/\r\rtypedef struct {\r    CM_ItemHeader       noteItem;           /* item header                  */\r\r    UWORD               noteDuration;       /* real duration, in ticks      */\r    UWORD               noteFlags;          /* various note flags           */\r\r    UBYTE               noteDivision;       /* formal note length           */\r\r    UBYTE               notePitch;          /* MIDI note number             */\r    UBYTE               notePitchMods;      /* modifications to pitch       */\r    BYTE                noteLevel;          /* vertical position            */\r\r    BYTE                noteBeamHeight;     /* y position of beam           */\r    UBYTE               noteStyle;          /* Note Style type              */\r} CM_Note;\r\r    /* macros to access the various bitfields */\r\r#define CM_NoteDots(f)          (((f).noteDivision >> 4) & 0x03)\r#define CM_NoteDivision(f)      ((f).noteDivision & 0x0f)\r\r#define CM_NoteAccidental(f)    ((f).notePitchMods & 7)\r#define CM_NoteTrill(f)         (((f).notePitchMods >> 3) & 7)\r#define CM_NoteArpeggiation(f)  (((f).notePitchMods >> 6) & 3)\r\r#define CM_SetNoteDivision(note, division, dots) \\r        ((note).noteDivision = (dots << 4) | division)\r\r#define CM_SetNotePitchMods(note, arp, trill, accidental) \\r        ((note).notePitchMods = (arp << 6) | ((trill << 3) & 7) | (accidental & 7))\r\r#define CM_RestPitch    255\r\renum note_dots {\r    NO_DOT = 0,                             /* Note is normal duration      */\r    DOTTED_NOTE = 1,                        /* Note is 50% longer           */\r    DOUBLE_DOTTED = 2                       /* note is 75% longer           */\r};\r\renum note_divisions {\r    DOUBLE_WHOLE_NOTE = 0,\r    WHOLE_NOTE,\r    HALF_NOTE,\r    QUARTER_NOTE,\r    EIGHTH_NOTE,\r    SIXTEENTH_NOTE,\r    NOTE_32,\r    NOTE_64,\r    NOTE_128,\r    NOTE_256\r};\r\renum note_accidentals {\r    NOTE_ACC_NONE=0,\r    NOTE_ACC_DOUBLE_FLAT,\r    NOTE_ACC_FLAT,\r    NOTE_ACC_HALF_FLAT,\r    NOTE_ACC_NATURAL,\r    NOTE_ACC_HALF_SHARP,\r    NOTE_ACC_SHARP,\r    NOTE_ACC_DOUBLE_SHARP,\r\r        /*  drum styles: used in place of accidental when NOTEF_DRUM is set.\r            Hollow symbols are used in place of "hollow" note heads, such\r            as half notes.\r\r            Note that the assignment of drum parts to symbols is arbtrary,\r            however the X symbol in jazz notation means "brush", and the\r            triangle symbol is often assigned to the triangle instrument.\r            Note also that normal note heads are often used for many\r            drum instruments.\r        */\r\r    NOTE_DRUM_X=0,                          /* An "x" instead of note head  */\r    NOTE_DRUM_DIAMOND,                      /* diamond shape                */\r    NOTE_DRUM_SQUARE,                       /* square box                   */\r    NOTE_DRUM_TRIANGLE,                     /* triangle                     */\r\r};\r\r    /*  trills and tremolos and other pitch modulations which can be attached\r        to a note. Note that these apply to the entire chord.\r    */\r\renum note_trills {\r    NOTE_PMOD_NONE=0,\r    NOTE_PMOD_TRILL,\r    NOTE_PMOD_MORDENT,\r    NOTE_PMOD_INV_MORDENT,\r    NOTE_PMOD_TURN,\r};\r\r    /*  Arpeggiation, indicated as a vertical sqiggly line before the chord */\r\renum note_arp_mods {\r    NOTE_ARPEGGIO = 1,\r    NOTE_REV_ARPEGGIO = 2,\r};\r\r    /* note style flags */\r\r#define NSTYLEF_STACCATO        (1<<0)      /* Staccatto mark ('.')         */\r#define NSTYLEF_STACCATISSIMO   (1<<1)      /* Staccattissimo mark (wedge)  */\r#define NSTYLEF_LEGATO          (1<<2)      /* Legato ('-')                 */\r#define NSTYLEF_SFORZANDO       (1<<3)      /* Szorzando ('^')              */\r#define NSTYLEF_ACCENT          (1<<4)      /* Accent ('>')                 */\r#define NSTYLEF_TENUTO          (1<<5)      /* Tenuto (short '-')           */\r\r    /* general note flags */\r\renum noteFlags {\r    NOTEF_STEMDOWN      = (1<<0),           /* Note's stem is down          */\r    NOTEF_BEAMED        = (1<<1),           /* Note is beamed with next note*/\r    NOTEF_TIED          = (1<<2),           /* Note is tied with next note  */\r    NOTEF_TIEDOWN       = (1<<3),           /* tie direction is DOWN        */\r    NOTEF_GRACE         = (1<<4),           /* display as grace note        */\r    NOTEF_CUE           = (1<<5),           /* display as cue note          */\r    NOTEF_DRUM          = (1<<6),           /* note has a drum head         */\r    NOTEF_STEMSET       = (1<<7),           /* Stem direction fixed by user */\r\r    NOTEF_RES1          = (1<<12),          /* reserved by DMCS for play    */\r    NOTEF_RES2          = (1<<13),          /*      styles (sorry :-)       */\r    NOTEF_RES3          = (1<<14),\r    NOTEF_RES4          = (1<<15),\r};\r\r/* ========================================================================= *\r                                 Filler item\r * ========================================================================= */\r\r    /*  This item is used for supporting sparse clips. The fillerDuration\r        field contains the total of the formal durations of the missing\r        items between the previous event and the next one.\r    */\r\rtypedef struct {\r    CM_ItemHeader       fillerItem;         /* item header                  */\r    UWORD               fillerDuration;     /* formal size of items left out*/\r} CM_Filler;\r\r/* ========================================================================= *\r                                 Dynamic Item\r * ========================================================================= */\r\r    /*  This item specifies a MIDI volume. Note that the relationship between\r        Volume and dynamic markings (such as fff, pp, etc) is defined\r        elsewhere.\r    */\r\rtypedef struct {\r    CM_ItemHeader       dynItem;            /* item header                  */\r    BYTE                dynLevelPos;        /* vertical position in leveks  */\r    UBYTE               dynVolume;          /* midi pressure number (0..127)*/\r    BYTE                dynSymbol;          /* dynamic symbol, see below    */\r    UBYTE               dynPad;\r} CM_Dynamic;\r\r    /*  Dynamic symbols:\r\r        0 = symbol not specified, derive from MIDI volume.\r        +1 = mf         -1 = mp\r        +2 = f          -2 = p\r        +3 = ff         -3 = pp\r        +4 = fff        -4 = ppp\r                (etc)\r    */\r\r/* ========================================================================= *\r                               Instrument item\r * ========================================================================= */\r\r    /*  Rather than embedding the instrument names in the actual score, a\r        seperate "instrument table" chunk will be defined.\r    */\r\rtypedef struct {\r    CM_ItemHeader       instItem;           /* instrument item              */\r    UBYTE               instNumber;         /* instrument number from table */\r    UBYTE               instPad;\r} CM_Instrument;\r\r/* ========================================================================= *\r                                  Tempo Item\r * ========================================================================= */\r\r    /*  For compatibility with Standard MIDI files, tempo is represented as\r        microseconds per quarter note, rather than the more commonly used\r        quarter notes per minute. To convert from one to the other, the\r        following formula works both ways:\r\r                T = 60,000,000 / t;\r\r        For accuracy, you may want to round:\r\r                T = (60,000,000 + t/2) / t;\r\r        Of course, the user interface of the program should not use units\r        like this.\r    */\r\rtypedef struct {\r    CM_ItemHeader       tempoItem;          /* item header                  */\r    ULONG               tempoValue;         /* new tempo value              */\r} CM_Tempo;\r\r/* ========================================================================= *\r                                 Repeat Item\r * ========================================================================= */\r\r    /*  This is a general category of items for jumping around in the\r        score in a non-sequential fashion. It includes things like\r        begin/end repeat bars, repeat measure, Da Capo, etc.\r\r        "repeatCount" is the number of times that the jump should occur,\r        not the total number of times a passage should be played. For example,\r        an begin/end repeat which is to play twice (once through, and then\r        prepeated once) should have a repeatCount of "1".\r\r        In addition, repeatCount should be associated with the jump rather\r        than the label. This imples that the count should go with the\r        "end" of a begin/end block rather than the "begin".\r    */\r\rtypedef struct {\r    CM_ItemHeader       repeatItem;         /* item header                  */\r    UBYTE               repeatType;         /* subtype of group             */\r    UBYTE               repeatCount;        /* number of times to jump      */\r} CM_Repeat;\r\renum repeat_types {\r    REPEAT_BLOCK_BEGIN=0,                   /* defines a repeat block       */\r    REPEAT_BLOCK_END,\r\r    REPEAT_LAST_MEASURE,                    /* jumps back 1 measure         */\r    REPEAT_LAST_TWO_MEASURES,               /* jumps back 2 measures        */\r\r    REPEAT_MEASURE_REST,                    /* rest for N measures          */\r                                            /* (not really a jump)          */\r        /* labels to go to */\r\r    REPEAT_LABEL_SEGNO,                     /* The "sign" D.S. refers to    */\r    REPEAT_LABEL_CODA,                      /* The Coda symbol              */\r\r        /* goto operators */\r\r    REPEAT_DC,                              /* D.C.                         */\r    REPEAT_DC_AL_FINE,                      /* D.C. al fine                 */\r    REPEAT_DS,                              /* D.S.                         */\r    REPEAT_DS_AL_FINE,                      /* D.S. al fine                 */\r    REPEAT_DS_AL_CODA,                      /* D.S. al coda                 */\r};\r\r/* ========================================================================= *\r                                   Group Item\r * ========================================================================= */\r\r    /*  A "Group" Item is defined as a Slur, Crescendo, or Octave Raiser.\r        In general, groups can apply to any contiguous range of notes\r        on a track, and groups of the same type can note overlap.\r\r        Note that in some cases, such as for example a crecendo, although\r        the modification is technically "attached" to a particular\r        track, it affects all the tracks on that staff.\r    */\r\rtypedef struct {\r    CM_ItemHeader       groupItem;          /* item header                  */\r    UBYTE               groupType;          /* subtype of group             */\r\r        /*  To even out the structure, we'll add an extra byte which means\r            different things based on the group type. Right now it is\r            only defined in the case of a crescendo / decrescendo in which\r            case it means the final volume.\r\r            For all others, it should be set to zero.\r        */\r\r    UBYTE               groupVal;\r} CM_Group;\r\r    /* Types of group items supported */\r\renum group_types {\r    GROUPTYPE_SLUR_UP=0,\r    GROUPTYPE_SLUR_DOWN,\r    GROUPTYPE_CRESCENDO,\r    GROUPTYPE_DECRESCENDO,\r    GROUPTYPE_OCTAVE_UP,                    /* "8va" symbol                 */\r    GROUPTYPE_OCTAVE_DOWN,                  /* "8vb" symbol                 */\r    GROUPTYPE_GLISSANDO_UP,\r    GROUPTYPE_GLISSANDO_DOWN,\r\r    GROUPTYPE_TUPLET,                       /* see below                    */\r    GROUPTYPE_TRILL,                        /* the one with the wavy line   */\r    GROUPTYPE_TREMOLO,                      /* Slashes below a beam         */\r};\r\r    /* Tuplets are a subtype of group items, and as such have an extended\r        structure. Unlike other group types, tuplet group items can be nested.\r\r        Note that for ending a tuplet, the extra fields are not required\r        and a normal "Group" structure can be used. Each tuplet ending\r        item matches the nearest previous unmatched tuplet item.\r    */\r\rtypedef struct {\r    CM_ItemHeader       tupletItem;         /* item header                  */\r    UBYTE               tupletType;         /* subtype of group             */\r\r        /*  tupletNumber indicates how many notes can fit in the space of\r            'tupletSpace'. For example, a triplet, i.e. "3 in the space of 2",\r            or 2/3 duration, can be represented as tupletNumber = 3,\r            tupletSpace = 2.\r        */\r\r    UBYTE               tupletNumber,       /* How manu items               */\r                        tupletSpace;        /* in the space of how many     */\r\r        /*  tupletDigits represents the binary number which should be\r            displayed above the tuplet; For example, for a triplet this\r            should be 3.\r        */\r\r    UBYTE               tupletDigits;       /* number to display            */\r\r        /*  tupletFlags is for later use when we want tuplets combined with\r            slurs / brackets. Currently there are no flags defined, so the\r            field should be all zeroes.\r        */\r\r    UBYTE               tupletFlags,        /* various flags                */\r                        tupletPad;\r} CM_Tuplet;\r\r/* ========================================================================= *\r                                    Tablature Item\r * ========================================================================= */\r\r    /*  The Tablature item is used for guitar, banjo or other fretted\r        instruments. It's a two-dimensional array of bits, which is drawn\r        as a grid indicating the exact placement of fingers.\r\r        In addition, most tablatures have the name of the chord placed above\r        the grid. This can be quite complex, looking something like this:\r\r                     7+6\r                C min\r\r        Which means: "C minor, with an added seventh and a raised sixth".\r    */\r\rtypedef struct {\r    CM_ItemHeader       tabItem;            /* item header                  */\r\r        /*  tabRoot is used to indicate the name of the chord placed above\r            the tablature. Note that the root can have superscripts, which\r            are defined elsewhere.\r\r            unsigned int    rootLetter      : 3,    -- A, B, C, etc.\r                            rootAccidental  : 2,    -- accidental of root\r                            rootType        : 3,    -- major, minor, etc.\r        */\r\r    UBYTE               tabRoot;            /* describes root of chord      */\r\r        /*  tabDimensions is a field of two 4 bit values, representing the\r            width and height of the tablature array. A dimension of (0,0)\r            indicates that only the chord symbol should be used.\r        */\r\r    UBYTE               tabDimensions;      /* width/height of tab array    */\r\r        /*  tabIntervals is an optional field -- if it's zero, it means that\r            the writing program wasn't sophisticated enough to set it.\r            (This is generally true for programs that are typographical\r            rather than musical in orientation).\r\r            The field used to exactly describe the intervals in the\r            chord above the root. Each interval may be:\r\r                0 - missing ( no interval)\r                1 - lowered ( one half-step below major chord position )\r                2 - normal  ( in the normal position for a major chord )\r                3 - raised  ( one half-step above major chord position )\r\r            unsigned int    chordThird      : 2,    -- (missing, -1, 0, +1)\r                            chordFifth      : 2,    -- (missing, -1, 0, +1)\r                            chordSeventh    : 2,    -- (missing, -1, 0, +1)\r                            chordNinth      : 2,    -- (missing, -1, 0, +1)\r                            chordEleventh   : 2,    -- (missing, -1, 0, +1)\r                            chordThirteenth : 2,    -- (missing, -1, 0, +1)\r                            chordFifteenth  : 2,    -- (missing, -1, 0, +1)\r                            chordValid      : 1,    -- TRUE if field valid\r                            chordPad        : 1;\r        */\r\r    UWORD               tabIntervals;       /* describes exact chord intervals*/\r\r        /*  tabArray is a byte array of finger positions.\r\r            Each byte represents a string. The value of the byte\r            can be from 0 (representing an open string), or 1-16\r            (representing a finger placed above the Nth fret). The high\r            4 bits are reserved for now, but may be used later to indicate\r            special placement of the fingers.\r\r            Note that the tabArray can be longer or shorter than 6 bytes,\r            up to a maximum of 16 strings. In such cases, the event length\r            stored in the CM_ItemHeader would be adjusted accordingly.\r        */\r\r    UBYTE               tabArray[6];        /* tablature array              */\r\r        /*  Following the tabArray field is an optional variable-length\r            ASCII string which is the actual text of the superscript,\r            such as "maj6+7".\r\r            The length of the string can be computed comparing the end of\r            the event with the end of the tab-array. Null termination is\r            not required.\r        */\r\r};\r\renum chord_accidentals {\r    CHORD_ACC_NONE=0,\r    CHORD_ACC_FLAT,\r    CHORD_ACC_NATURAL,\r    CHORD_ACC_SHARP\r};\r\renum chord_types {\r    CHORD_TYPE_MAJOR,\r    CHORD_TYPE_MINOR,\r    CHORD_TYPE_DIMINISHED,\r    CHORD_TYPE_AUGMENTED,\r    CHORD_TYPE_SUSPENDED\r};\r\renum chord_letters {\r    CHORD_LETTER_A=0,\r    CHORD_LETTER_B,\r    CHORD_LETTER_C,\r    CHORD_LETTER_D,\r    CHORD_LETTER_E,\r    CHORD_LETTER_F,\r    CHORD_LETTER_G\r};\r\r/* ========================================================================= *\r                           Lyric Font Chunk (LFON)\r\r    This section describes the data structures which are used in the CMUS\r    'LFON' Chunk.\r\r    LFON chunks are used to store the font table for the document. Embedded\r    within the Lyric, Annotation and title chunks are font specifiers which\r    refer to a given font by number. That number is an index into this table.\r\r    There is one LFON chunk per font. Each LFON chunk consists of the following\r    header, and then the name of the font. The terminating NULL should be\r    included in the font name.\r\r * ========================================================================= */\r\rtypedef struct {\r    UWORD               fontNumber;             /* number assigned to font  */\r    UWORD               fontHeight;             /* height of font in points */\r\r    /* fontName follows */\r\r} CM_FontEntry;\r\r/* ========================================================================= *\r                              Lyric Chunk (LYRC)\r\r    This section describes the data structures which are used in the CMUS\r    'LYRC' Chunk.\r\r    Each lyric is associated with a particular track, and a particular measure\r    within that track. The reason for this is because certain elements within\r    the lyrics can be "attached" to notes within a track, so that syllables\r    of the lyric can properly appear under the notes.\r\r    Lyrics associated with a particular track are written immediately after\r    that track. In other words, when reading a lyric, it should be associated\r    with the previously read track.\r\r * ========================================================================= */\r\r    /*  This is the header structure for a lyric. It is followed by the actual\r        text of the lyric. No terminating NUL is used.\r\r        Attaching syllables to notes: This is an optional feature which need\r        not be supported by all readers. Basically, the TAB character is used\r        to specify a block of text to align with the next note. Essentially,\r        each chord on the trackÊacts as a center-justified tab-stop. This is\r        similar to the way tab stops work on medium- to high-end word\r        processors: All the text between a tab, and the next tab (or the end\r        of the line) is "centered" at the tab-stop position. Readers\r        which don't wish to deal with this level of complexity can just\r        treat the tab as a space.\r    */\r\rtypedef struct {\r    UWORD               lyricMeasure;       /* starting measure of lyric    */\r\r        /*  Position of the upper-left coordinate of the lyric.\r            This can be positive or negative, and is interpreted just like\r            the 'itemXPos' field for track events.\r        */\r\r    WORD                lyricXPos;          /* position relative to measure */\r\r        /*  lyricLevel is the position, in micrometers, of the upper-\r            left corner of the lyric's extent box.\r\r            lyricHeight is also in micrometers.\r        */\r\r    Micrometers         lyricLevel,         /* distance from center of staff*/\r                        lyricHeight;        /* height of lyric extent       */\r\r        /*  Width is in micrometers. */\r\r    Micrometers         lyricWidth;\r\r        /* lyric text string follows */\r\r} CM_Lyric;\r\r    /*  Codes for specification of fonts and text styles. The "newfont" code\r        is followed by the font number. If no font is specified, font #0 is\r        the default.\r    */\r\renum {\r    LSTYLE_BOLD_ON=0x80,\r    LSTYLE_BOLD_OFF,\r    LSTYLE_ITALIC_ON,\r    LSTYLE_ITALIC_OFF,\r    LSTYLE_UNDER_ON,\r    LSTYLE_UNDER_OFF,\r    LSTYLE_NEWFONT,                             /* font number follows      */\r};\r\r/* ========================================================================= *\r                             Annotation chunks (ANOT)\r\r    This section describes the data structures which are used in the CMUS\r    'ANOT' Chunk. Note that there is a standard IFF chunk called 'ANNO'\r    which can be added to any file to annotate the file. The 'ANOT' is\r    used to specify annotations to the music, not to the file.\r\r * ========================================================================= */\r\r    /*  Annotation chunks are specified exactly like Lyric chunks. The only\r        reason for distinguishing between the two is that a "stripper" program\r        might want to strip out one or the other.\r    */\r\r/* ========================================================================= *\r                               Title Chunk (TITL)\r\r    This section describes the data structures which are used in the CMUS 'TITL'\r    Chunk. Unlike Lyrics, Titles are placed at fixed positions on the page\r    (generally at the top) and are are not adjusted based on the positioning\r    of any particular measure.\r\r * ========================================================================= */\r\r    /*  Title chunks are specified exactly like Lyric chunks, except that the\r        lyricMeasure field is ignored and should be set to 0.\r\r        In particular, the lyricXPos field is no longer based on measure width,\r        but is now a fractional width of the document. Similarly, the\r        lyricLevel field is the number of levels from the top of the page.\r        (Or should that be an absolute measure?)\r    */\r\r/* ========================================================================= *\r                          CMUS Instrument Table (FORM INST)\r\r        The instrument table fo the CMUS form is stored as an embedded FORM\r    called 'INST'. Each instrument in the table is one INST form.\r\r        Instruments can be configured for MIDI, internal audio, or both.\r    When using internal sounds, samples can be sepcified using an embedded\r    FORM 8SVX, or any other IFF sampled sound FORM that the program wishes\r    to support. Sampled sounds can be embedded in the file, or external\r    sample files can be referenced from within the file, by pathname.\r\r        Here's a summary of the chunks which can be included in an INST\r    form:\r\r        'INHD': This is the instrument header. It contains the instrument\r            number, and the various MIDI-related parameters. The chunk\r            format is defined below.\r\r        'FORM 8SVX': This is an embedded sampled sound file. The sampled\r            sound is to be associated with the instrument.\r\r        'SFIL': This is a reference to a sampled sound in a different file,\r            and can be used instead of an embedded sample. The chunk format\r            is simply the name of the file. If the file contains more than\r            one sample, only the first is used. (A different chunk can be\r            defined to select the Nth sample, if it turns out that this\r            feature might be desired).\r\r        'SHAR': This allows a instrument to share a sampled sound with\r            another instrument. This would be used instead of either and\r            embedded sample or an 'SFIL' chunk. The chunk format is simple\r            a UWORD of the instrument number to share with; This\r            instrument must have been previously loaded.\r\r        'ATAK': Identical with the ATAK chunk in FORM 8SVX, this allows\r            the instrument have a different envelope than the one in\r            the sampled sound file.\r\r        'RLSE': Identical with the RLSE chunk in FORM 8SVX, this allows the\r            instrument have a different envelope than the one in the\r            sampled sound file.\r\r        'NAME': is a standard chunk which can be added to any IFF FORM.\r            In this case, it is used to store the instrument name. Other\r            standard chunks which can be added are "AUTH" (author name),\r            "VERS" (version string), "ANNO" (Annotations) and "(C) "\r            (copyright notice).\r\r    Note: If there is no sampled sound specified, either through an\r        embedded sample or SFIL or SHAR chunks, then this instrument is\r        a MIDI-only instrument.\r\r * ========================================================================= */\r\r    /* Instrument header chunk -- INHD */\r\rtypedef struct {\r\r        /*  'instNumber' corresponds to the instrument number used\r            in the "instrument event" in the TRCK chunk.\r        */\r\r    UBYTE               instNumber;\r\r    UBYTE               instFlags;          /* various flags                */\r    WORD                instTune;           /* tuning, in 1/100 semitones   */\r    WORD                instVolume;         /* overall volume, 0-0xffff     */\r\r        /*  "Pan" can be used by both MIDI and sampled sound instruments, and\r            indicates a preferences for left or right. It ranges from 0 to\r            127 (same as MIDI), with 0 being ?? and 127 being ??.\r        */\r\r    UBYTE               instPan;\r\r        /*  MIDI-related variables */\r\r    UBYTE               instMidiChannel;    /* MIDI channel to use          */\r    UBYTE               instMidiPreset;     /* MIDI Preset for this channel */\r    UBYTE               instMidiPort;       /* Hardware port #, if applies  */\r\r} InstrumentHeader;\r\r#define INST_MAXVOL     0x0ffff\r#define INST_MAXPAN     127\r\r    /* various flags for instFlags */\r\r#define INSTF_MIDI      (1<<0)              /* MIDI is enabled              */\r#define INSTF_MIDIVOL   (1<<1)              /* use MIDI volume, not velocity*/\r\r#endif\r
\ No newline at end of file
diff --git a/ekit/com/hexidec/util/CMUScodec.java b/ekit/com/hexidec/util/CMUScodec.java
new file mode 100644 (file)
index 0000000..da300fd
--- /dev/null
@@ -0,0 +1 @@
+/*\rGNU General Public License\r\rCMUScodec\rCopyright (C) 2002  Howard A Kistler\r\rThis program is free software; you can redistribute it and/or\rmodify it under the terms of the GNU General Public License\ras published by the Free Software Foundation; either version 2\rof the License, or (at your option) any later version.\r\rThis program is distributed in the hope that it will be useful,\rbut WITHOUT ANY WARRANTY; without even the implied warranty of\rMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\rGNU General Public License for more details.\r\rYou should have received a copy of the GNU General Public License\ralong with this program; if not, write to the Free Software\rFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\r*/\r\rpackage com.hexidec.util;\r\rimport java.awt.AWTException;\rimport java.io.File;\rimport java.io.FileInputStream;\rimport java.io.FileNotFoundException;\rimport java.io.FileOutputStream;\rimport java.io.FileWriter;\rimport java.io.IOException;\r\r/** CMUScodec\r  *\r  * Utility for reading (and eventually converting) Deluxe Music\r  * Construction Set (DMCS) files\r  *\r  * @author Howard Kistler\r  * @version 0.1\r  *\r  * VERSION HISTORY\r  * 0.1 (03/13/2002) - initial creation (03/13/2002)\r  */\r\rpublic class CMUScodec\r{\r\r//  Constants ---------------------------------------------------------------------------->\r\r/*\r       CMUS File Structure\r\r   FILE HEADER\r    ====================\r   (At the beginning of each file)\r\r       IFF Form Chunk\r         4 bytes - FORM\r         4 bytes - ?\r            4 bytes - CMUS\r\r        Score Header Chunk\r             4 bytes - SCHD\r         10 bytes - 00 00 00 1A 00 02 00 00 00 02\r               2 bytes - (significant number[s]?)\r             2 bytes - 00 04 (# of channels maybe?)\r         2 bytes - Ch\r           12 bytes - 00 00 00 00 00 00 0C E6 00 00 0C E6\r         2 bytes - (2 byte significant number, or 00 and 1 byte significant?)\r\r  DSCR HEADER BLOCK\r              4 bytes - DSCR\r         14 bytes - ?\r\r  Staff Table Chunk\r              4 bytes - STAF\r         X bytes - ? (1 entry per staff in score)\r\r      DSTF HEADER BLOCK\r              4 bytes - DSTF\r         X bytes - ?\r\r   LFON HEADER BLOCK\r              4 bytes - LFON\r         4 bytes - 00 00 00 0F\r          4 bytes - 00 00 00 08\r          X bytes - Font Name\r            2 bytes - 00 00\r\r       SONG BODY\r      ====================\r\r  TRCK BLOCKS\r            4 bytes - TRCK\r         X bytes - track data\r\r  INSTRUMENT BLOCK\r       ====================\r\r  Each Instrument Contains:\r              4 bytes - FORM\r         4 bytes - (number?)\r            8 bytes - INSTINHD\r             4 bytes - 00 00 00 0A\r          1 byte  - Instrument Number\r            1 byte  - (zero pad?)\r          8 bytes - 00 00 FF FF 40 00 00 00\r              4 bytes - NAME\r         4 bytes - Name Byte Count\r              Y bytes - Name Bytes (Y = value from above)\r            1 byte  - (zero pad?)\r          [Optional Instrument Path]\r                     4 bytes - SFIL\r                 4 bytes - Path Byte Count\r                      Y bytes - Path Bytes (Y = value from above)\r            1 byte  - (zero pad)\r\r*/\r\r      // Decoder Vars\r        private static byte[] bData;\r   private static int iPlace;\r\r//  Public Vartypes ---------------------------------------------------------------------->\r\r       public final static int FILETYPE_DMCS   = 0;\r   public final static int FILETYPE_CMUS   = 1;\r   public final static int FILETYPE_SMUS   = 2;\r   public final static int FILETYPE_TEXT   = 3;\r   public final static int FILETYPE_FINALE = 4;\r\r  private final static byte NUL = (byte)0;\r\r//  Constructor -------------------------------------------------------------------------->\r\r public CMUScodec()\r     {\r      }\r\r//  Decode Method ------------------------------------------------------------------------>\r\r        public static void decode(String sourceFile, String destFile)\r  throws FileNotFoundException, IOException, AWTException\r        {\r              convertToTextFile(sourceFile, destFile);\r       }\r\r//  Encode Method ------------------------------------------------------------------------>\r\r        public static void encode(String sourceFile, String destFile, int fileType)\r    throws FileNotFoundException, IOException, AWTException\r        {\r//            String newFormat = convertToFormat(sourceFile, fileType);\r//            writeToDMCSFile(newFormat, destFile);\r  }\r\r//  CMUS-to-TEXT File Conversion -------------------------------------------------------->\r\r protected static void convertToTextFile(String inFile, String outFile)\r throws IOException\r     {\r              File srcFile = new File(inFile);\r               FileInputStream fis = new FileInputStream(srcFile);\r            int filesize = (int)(srcFile.length());\r                bData = new byte[filesize];\r            iPlace = 0;\r            int iCounter = 0;\r              while(iCounter < filesize)\r             {\r                      bData[iCounter] = (byte)(fis.read());\r                  iCounter++;\r            }\r              fis.close();\r\r          FileWriter fw = new FileWriter(new File(outFile));\r\r            String sOutput = "FILE SIZE  : " + srcFile.length() + "\r";\r            fw.write(sOutput, 0, sOutput.length());\r\r               sOutput = "BYTES READ : " + iCounter + "\r";\r           fw.write(sOutput, 0, sOutput.length());\r\r               sOutput = "====================\rFILE CONTENTS\r====================\r";\r               fw.write(sOutput, 0, sOutput.length());\r\r               while(iPlace < iCounter)\r               {\r                      String chunk = "" + (char)(bData[iPlace++]) + (char)(bData[iPlace++]) + (char)(bData[iPlace++]) + (char)(bData[iPlace++]);\r                     if     (chunk.equals("FORM")) { parseFORM(fw); }\r                       else if(chunk.equals("SCHD")) { parseSCHD(fw); }\r                       else if(chunk.equals("DSCR")) { parseDSCR(fw); }\r                       else if(chunk.equals("STAF")) { parseSTAF(fw); }\r                       else if(chunk.equals("DSTF")) { parseDSTF(fw); }\r                       else if(chunk.equals("LFON")) { parseLFON(fw); }\r                       else if(chunk.equals("TRCK")) { parseTRCK(fw); }\r                       else if(chunk.equals("INHD")) { parseINHD(fw); }\r                       else if(chunk.equals("NAME")) { parseNAME(fw); }\r                       else if(chunk.equals("SFIL")) { parseSFIL(fw); }\r                       else\r                   { \r                             sOutput = "UNKNOWN CHUNK : " + chunk + "\r";\r                           fw.write(sOutput, 0, sOutput.length());\r                                iPlace = iCounter;\r                             break;\r                 }\r              }\r/*\r           4 bytes - FORM\r         4 bytes - (number?)\r            4 bytes - INST\r         4 bytes - type : INHD, SFIL, SHAR or others\r            4 bytes - 00 00 00 0A\r          1 byte  - Instrument Number\r            1 byte  - (zero pad?)\r          8 bytes - 00 00 FF FF 40 00 00 00\r              4 bytes - NAME\r         4 bytes - Name Byte Count\r              Y bytes - Name Bytes (Y = value from above)\r            1 byte  - (zero pad?)\r          [Optional Instrument Path]\r                     4 bytes - SFIL\r                 4 bytes - Path Byte Count\r                      Y bytes - Path Bytes (Y = value from above)\r            1 byte  - (zero pad)\r*/\r\r               fw.flush();\r            fw.close();\r    }\r\r//  Chunk Parsing Methods---------------------------------------------------------------->\r\r private static void parseFORM(FileWriter fw)\r   throws IOException\r     {\r              String sOutput = "--------------------\rFORM CHUNK\r--------------------\r";\r           fw.write(sOutput, 0, sOutput.length());\r\r               sOutput = "FORM BLOCK : FORM\r";\r               fw.write(sOutput, 0, sOutput.length());\r\r               int iSize =\r                    (int)(\r                         ((bData[iPlace++]) << 24) +\r                            ((bData[iPlace++]) << 16) +\r                            ((bData[iPlace++]) <<  8) +\r                            ((bData[iPlace++])      )\r                              );\r             sOutput = "SIZE BLOCK : " + iSize + "\r";\r              fw.write(sOutput, 0, sOutput.length());\r\r               sOutput = "TYPE BLOCK : " + (char)(bData[iPlace++]) + (char)(bData[iPlace++]) + (char)(bData[iPlace++]) + (char)(bData[iPlace++]) + "\r";\r              fw.write(sOutput, 0, sOutput.length());\r        }\r\r     private static void parseSCHD(FileWriter fw)\r   throws IOException\r     {\r              String sOutput = "--------------------\rSCORE HEADER CHUNK\r--------------------\r";\r           fw.write(sOutput, 0, sOutput.length());\r\r               sOutput = "SCHD BLOCK : SCHD\r";\r               fw.write(sOutput, 0, sOutput.length());\r\r               int iData =\r                    (int)(\r                         ((bData[iPlace++]) <<  8) +\r                            ((bData[iPlace++])      )\r                              );\r             sOutput = "WORD BLOCK 1 : " + iData + "\r";\r            fw.write(sOutput, 0, sOutput.length());\r\r               iData =\r                        (int)(\r                         ((bData[iPlace++]) <<  8) +\r                            ((bData[iPlace++])      )\r                              );\r             sOutput = "WORD BLOCK 2 : " + iData + "\r";\r            fw.write(sOutput, 0, sOutput.length());\r\r               iData =\r                        (int)(\r                         ((bData[iPlace++]) <<  8) +\r                            ((bData[iPlace++])      )\r                              );\r             sOutput = "WORD BLOCK 3 : " + iData + "\r";\r            fw.write(sOutput, 0, sOutput.length());\r\r               iData =\r                        (int)(\r                         ((bData[iPlace++]) <<  8) +\r                            ((bData[iPlace++])      )\r                              );\r             sOutput = "WORD BLOCK 4 : " + iData + "\r";\r            fw.write(sOutput, 0, sOutput.length());\r\r               iData =\r                        (int)(\r                         ((bData[iPlace++]) <<  8) +\r                            ((bData[iPlace++])      )\r                              );\r             sOutput = "WORD BLOCK 5 : " + iData + "\r";\r            fw.write(sOutput, 0, sOutput.length());\r\r               sOutput = "BYTE 6a: " + bData[iPlace++] + "\r";\r                fw.write(sOutput, 0, sOutput.length());\r                sOutput = "BYTE 6b: " + bData[iPlace++] + "\r";\r                fw.write(sOutput, 0, sOutput.length());\r\r               iData =\r                        (int)(\r                         ((bData[iPlace++]) <<  8) +\r                            ((bData[iPlace++])      )\r                              );\r             sOutput = "WORD BLOCK 7+: " + iData + "\r";\r            fw.write(sOutput, 0, sOutput.length());\r\r               sOutput = "Ch BLOCK : " + (char)(bData[iPlace++]) + (char)(bData[iPlace++]) + "\r";\r            fw.write(sOutput, 0, sOutput.length());\r\r               for(int i = 0; i < 6; i++)\r             {\r                      iData =\r                                (int)(\r                                 ((bData[iPlace++]) <<  8) +\r                                    ((bData[iPlace++])      )\r                                      );\r                     sOutput = "SUB WORD " + (i + 1) + ": " + iData + "\r";\r                 fw.write(sOutput, 0, sOutput.length());\r                }\r\r             iData =\r                        (int)(\r                         ((bData[iPlace++]) <<  8) +\r                            ((bData[iPlace++])      )\r                              );\r             sOutput = "SUB WORD 7 : " + iData + "\r";\r              fw.write(sOutput, 0, sOutput.length());\r        }\r\r     private static void parseDSCR(FileWriter fw)\r   throws IOException\r     {\r              String sOutput = "--------------------\rDSCR CHUNK\r--------------------\r";\r           fw.write(sOutput, 0, sOutput.length());\r\r               sOutput = "DSCR BLOCK : DSCR\r";\r               fw.write(sOutput, 0, sOutput.length());\r\r               for(int i = 0; i < 7; i++)\r             {\r                      int iData =\r                            (int)(\r                                 ((bData[iPlace++]) <<  8) +\r                                    ((bData[iPlace++])      )\r                                      );\r                     sOutput = "DSCR WORD " + i + ": " + iData + "\r";\r                      fw.write(sOutput, 0, sOutput.length());\r                }\r      }\r\r     private static void parseSTAF(FileWriter fw)\r   throws IOException\r     {\r              String sOutput = "--------------------\rSTAFF TABLE CHUNK\r--------------------\r";\r            fw.write(sOutput, 0, sOutput.length());\r\r               sOutput = "STAF BLOCK : STAF\r";\r               fw.write(sOutput, 0, sOutput.length());\r\r               int iStaffLeadByte =\r                   (int)(\r                         (bData[iPlace++] <<  8) +\r                              (bData[iPlace++]      )\r                                );\r             sOutput = "STAF Lead Byte : " + iStaffLeadByte + "\r";\r         fw.write(sOutput, 0, sOutput.length());\r\r               int iStaffByteCount =\r                  (int)(\r                         (bData[iPlace++] <<  8) +\r                              (bData[iPlace++]      )\r                                );\r             sOutput = "STAF Byte Count : " + iStaffByteCount + "\r";\r               fw.write(sOutput, 0, sOutput.length());\r\r               for(int i = 0; i < iStaffByteCount; i++)\r               {\r                      sOutput = "STAF Byte " + (i+1) + " : " + bData[iPlace++] + "\r";\r                       fw.write(sOutput, 0, sOutput.length());\r                }\r      }\r\r     private static void parseDSTF(FileWriter fw)\r   throws IOException\r     {\r              String sOutput = "--------------------\rDSTF CHUNK\r--------------------\r";\r           fw.write(sOutput, 0, sOutput.length());\r\r               sOutput = "DSTF BLOCK : DSTF\r";\r               fw.write(sOutput, 0, sOutput.length());\r\r               int iDstaffLeadByte =\r                  (int)(\r                         (bData[iPlace++] <<  8) +\r                              (bData[iPlace++]      )\r                                );\r             sOutput = "DSTF Lead Byte : " + iDstaffLeadByte + "\r";\r                fw.write(sOutput, 0, sOutput.length());\r\r               int iDstaffByteCount =\r                 (int)(\r                         (bData[iPlace++] <<  8) +\r                              (bData[iPlace++]      )\r                                );\r             sOutput = "DSTF Byte Count : " + iDstaffByteCount + "\r";\r              fw.write(sOutput, 0, sOutput.length());\r\r               for(int i = 0; i < iDstaffByteCount; i++)\r              {\r                      sOutput = "DSTF Byte " + (i+1) + " : " + bData[iPlace++] + "\r";\r                       fw.write(sOutput, 0, sOutput.length());\r                }\r      }\r\r     private static void parseLFON(FileWriter fw)\r   throws IOException\r     {\r              String sOutput = "--------------------\rLYRIC FONT CHUNK\r--------------------\r";\r             fw.write(sOutput, 0, sOutput.length());\r\r               sOutput = "LFON BLOCK : LFON\r";\r               fw.write(sOutput, 0, sOutput.length());\r\r               int iFontNumber =\r                      (int)(\r                         ((bData[iPlace++]) << 24) +\r                            ((bData[iPlace++]) << 16) +\r                            ((bData[iPlace++]) <<  8) +\r                            ((bData[iPlace++])      )\r                              );\r             sOutput = "FONT NUMBER : " + iFontNumber + "\r";\r               fw.write(sOutput, 0, sOutput.length());\r\r               int iFontHeight =\r                      (int)(\r                         ((bData[iPlace++]) << 24) +\r                            ((bData[iPlace++]) << 16) +\r                            ((bData[iPlace++]) <<  8) +\r                            ((bData[iPlace++])      )\r                              );\r             sOutput = "FONT HEIGHT : " + iFontHeight + "\r";\r               fw.write(sOutput, 0, sOutput.length());\r\r               sOutput = "Font Name : ";\r              while(bData[iPlace++] != NUL)\r          {\r                      sOutput = sOutput + (char)(bData[iPlace-1]);\r           }\r              sOutput = sOutput + "\r";\r              fw.write(sOutput, 0, sOutput.length());\r\r               sOutput = "[TERMNUL] : " + bData[iPlace++] + "\r";\r             fw.write(sOutput, 0, sOutput.length());\r        }\r\r     private static void parseTRCK(FileWriter fw)\r   throws IOException\r     {\r              String sOutput = "--------------------\rTRACK CHUNK\r--------------------\r";\r          fw.write(sOutput, 0, sOutput.length());\r\r               sOutput = "TRCK BLOCK : TRCK\r";\r               fw.write(sOutput, 0, sOutput.length());\r\r               int iTrackLeadByte =\r                   (int)(\r                         (bData[iPlace++] <<  8) +\r                              (bData[iPlace++]      )\r                                );\r             sOutput = "TRCK Lead Byte : " + iTrackLeadByte + "\r";\r         fw.write(sOutput, 0, sOutput.length());\r\r               int iTrackByteCount =\r                  (int)(\r                         (bData[iPlace++] <<  8) +\r                              (bData[iPlace++]      )\r                                );\r             sOutput = "TRCK Byte Count : " + iTrackByteCount + "\r";\r               fw.write(sOutput, 0, sOutput.length());\r\r               int iTrackStaff =\r                      (int)(\r                         (bData[iPlace++] <<  8) +\r                              (bData[iPlace++]      )\r                                );\r             sOutput = "TRCK Staff : " + iTrackStaff + "\r";\r                fw.write(sOutput, 0, sOutput.length());\r\r               int iTrackTrack =\r                      (int)(\r                         (bData[iPlace++] <<  8) +\r                              (bData[iPlace++]      )\r                                );\r             sOutput = "TRCK Track : " + iTrackTrack + "\r";\r                fw.write(sOutput, 0, sOutput.length());\r\r               int iTrackFlags =\r                      (int)(\r                         (bData[iPlace++] <<  8) +\r                              (bData[iPlace++]      )\r                                );\r             sOutput = "TRCK Flags : " + iTrackFlags + "\r";\r                fw.write(sOutput, 0, sOutput.length());\r\r               int iTrackTransposition =\r                      (int)(\r                         (bData[iPlace++] <<  8) +\r                              (bData[iPlace++]      )\r                                );\r             sOutput = "TRCK Trans : " + iTrackTransposition + "\r";\r                fw.write(sOutput, 0, sOutput.length());\r\r               for(int i = 0; i < iTrackByteCount - 8;)\r               {\r                      int iItemLength = (int)(bData[iPlace++]);\r                      sOutput = "ITEM LEN  : " + iItemLength + "\r";\r                 fw.write(sOutput, 0, sOutput.length());\r                        i++;\r\r                  sOutput = "ITEM TYPE : " + bData[iPlace++] + "\r";\r                     fw.write(sOutput, 0, sOutput.length());\r                        i++;\r\r                  int iItemXPos =\r                                (int)(\r                                 (bData[iPlace++] <<  8) +\r                                      (bData[iPlace++]      )\r                                        );\r                     sOutput = "ITEM XPOS : " + iItemXPos + "\r";\r                   fw.write(sOutput, 0, sOutput.length());\r                        i++;i++;\r\r                      int iItemStart =\r                               (int)(\r                                 (bData[iPlace++] <<  8) +\r                                      (bData[iPlace++]      )\r                                        );\r                     sOutput = "ITEM START: " + iItemStart + "\r";\r                  fw.write(sOutput, 0, sOutput.length());\r                        i++;i++;\r\r                      for(int j = 0; j < iItemLength - 3; j++)\r                       {\r                              int iItemData =\r                                        (int)(\r                                         (bData[iPlace++] <<  8) +\r                                              (bData[iPlace++]      )\r                                                );\r                             sOutput = "ITEM WORD " + j + " : " + iItemData + "\r";\r                         fw.write(sOutput, 0, sOutput.length());\r                                i++;i++;\r                       }\r              }\r      }\r\r     private static void parseINHD(FileWriter fw)\r   throws IOException\r     {\r              String sOutput = "--------------------\rINSTRUMENT HEADER CHUNK\r--------------------\r";\r              fw.write(sOutput, 0, sOutput.length());\r\r               sOutput = "INHD BLOCK : INHD\r";\r               fw.write(sOutput, 0, sOutput.length());\r\r               int iPadding =\r                 (int)(\r                         (bData[iPlace++] <<  8) +\r                              (bData[iPlace++]      )\r                                );\r             sOutput = "(HEADPAD)  : " + iPadding + "\r";\r           fw.write(sOutput, 0, sOutput.length());\r                byte instrumentNumber = bData[iPlace++];\r               sOutput = "INST #     : " + instrumentNumber + "\r";\r           fw.write(sOutput, 0, sOutput.length());\r                byte instrumentFlags  = bData[iPlace++];\r               sOutput = "INST FLAGS : " + instrumentFlags + "\r";\r            fw.write(sOutput, 0, sOutput.length());\r                int  instrumentTune   =\r                        (int)(\r                         (bData[iPlace++] <<  8) +\r                              (bData[iPlace++]      )\r                                );\r             sOutput = "INST TUNE  : " + instrumentTune + "\r";\r             fw.write(sOutput, 0, sOutput.length());\r                int  instrumentVolume =\r                        (int)(\r                         (bData[iPlace++] <<  8) +\r                              (bData[iPlace++]      )\r                                );\r             sOutput = "INST VOL   : " + instrumentVolume + "\r";\r           fw.write(sOutput, 0, sOutput.length());\r                byte instrumentPan = bData[iPlace++];\r          sOutput = "INST PAN   : " + instrumentNumber + "\r";\r           fw.write(sOutput, 0, sOutput.length());\r                byte instrumentMIDIChannel = bData[iPlace++];\r          sOutput = "MIDI CHAN   : " + instrumentNumber + "\r";\r          fw.write(sOutput, 0, sOutput.length());\r                byte instrumentMIDIPreset = bData[iPlace++];\r           sOutput = "MIDI PRESET : " + instrumentNumber + "\r";\r          fw.write(sOutput, 0, sOutput.length());\r                byte instrumentMIDIPort = bData[iPlace++];\r             sOutput = "MIDI PORT   : " + instrumentNumber + "\r";\r          fw.write(sOutput, 0, sOutput.length());\r                iPadding =\r                     (int)(\r                         (bData[iPlace++] <<  8) +\r                              (bData[iPlace++]      )\r                                );\r             sOutput = "(TAILPAD)  : " + iPadding + "\r";\r           fw.write(sOutput, 0, sOutput.length());\r        }\r\r     private static void parseNAME(FileWriter fw)\r   throws IOException\r     {\r              String sOutput = "--------------------\rINSTRUMENT NAME CHUNK\r--------------------\r";\r                fw.write(sOutput, 0, sOutput.length());\r\r               sOutput = "NAME BLOCK : NAME\r";\r               fw.write(sOutput, 0, sOutput.length());\r\r               int iNameHeadInt =\r                     (int)(\r                         (bData[iPlace++] <<  8) +\r                              (bData[iPlace++]      )\r                                );\r             sOutput = "NAME HEAD  : " + iNameHeadInt + "\r";\r               fw.write(sOutput, 0, sOutput.length());\r\r               int iNameByteCount =\r                   (int)(\r                         (bData[iPlace++] <<  8) +\r                              (bData[iPlace++]      )\r                                );\r             sOutput = "NAME BYTES : " + iNameByteCount + "\r";\r             fw.write(sOutput, 0, sOutput.length());\r\r               sOutput = "Instrument Name : ";\r                for(int i = 1; i < iNameByteCount; i++)\r                {\r                      sOutput = sOutput + (char)(bData[iPlace++]);\r           }\r              sOutput = sOutput + "\r";\r              fw.write(sOutput, 0, sOutput.length());\r\r               sOutput = "(PADNUL1)  : " + bData[iPlace++] + "\r";\r            fw.write(sOutput, 0, sOutput.length());\r\r               if((int)(iNameByteCount / 2.0) < (iNameByteCount / 2.0))\r               {\r                      sOutput = "(PADNUL2)  : " + bData[iPlace++] + "\r";\r                    fw.write(sOutput, 0, sOutput.length());\r                }\r      }\r\r     private static void parseSFIL(FileWriter fw)\r   throws IOException\r     {\r              String sOutput = "--------------------\rINSTRUMENT SAMPLE FILE CHUNK\r--------------------\r";\r         fw.write(sOutput, 0, sOutput.length());\r\r               sOutput = "SFIL BLOCK : SFIL\r";\r               fw.write(sOutput, 0, sOutput.length());\r\r               int iSampleFileBytes =\r                 (int)(\r                         ((bData[iPlace++]) << 24) +\r                            ((bData[iPlace++]) << 16) +\r                            ((bData[iPlace++]) <<  8) +\r                            ((bData[iPlace++])      )\r                              );\r             sOutput = "SFIL BYTES : " + iSampleFileBytes + "\r";\r           fw.write(sOutput, 0, sOutput.length());\r\r               sOutput = "Sample File Name : ";\r               for(int i = 1; i < iSampleFileBytes; i++)\r              {\r                      sOutput = sOutput + (char)(bData[iPlace++]);\r           }\r              sOutput = sOutput + "\r";\r              fw.write(sOutput, 0, sOutput.length());\r\r               sOutput = "(PADNUL)   : " + bData[iPlace++] + "\r";\r            fw.write(sOutput, 0, sOutput.length());\r        }\r\r//  File Write Method ------------------------------------------------------------------->\r\r protected static void writeToDMCSFile(String fileData, String outFile)\r throws IOException\r     {\r/*\r           FileOutputStream fos = new FileOutputStream(new File(outFile));\r\r               byte FileSizeByte1 = (byte)(fileData.length()         & 0xFF);\r         byte FileSizeByte2 = (byte)((fileData.length() >> 8)  & 0xFF);\r         byte FileSizeByte3 = (byte)((fileData.length() >> 16) & 0xFF);\r         byte FileSizeByte4 = (byte)((fileData.length() >> 24) & 0xFF);\r\r                byte[] DMCSFileHeader = new byte[]\r             {\r                      FileHeaderFormWord[0], FileHeaderFormWord[1], FileHeaderFormWord[2], FileHeaderFormWord[3],\r                    FileSizeByte1,         FileSizeByte2,         FileSizeByte3,         FileSizeByte4,\r                    FileHeaderTypeWord[0], FileHeaderTypeWord[1], FileHeaderTypeWord[2], FileHeaderTypeWord[3],\r                    FileHeaderOSAMWord[0], FileHeaderOSAMWord[1], FileHeaderOSAMWord[2], FileHeaderOSAMWord[3],\r                    FileHeaderTailWord[0], FileHeaderTailWord[1], FileHeaderTailWord[2], FileHeaderTailWord[3]\r             };\r             fos.write(DMCSFileHeader);\r\r            byte BitmapWidthByte1      = (byte)(IntBitmapWidth          & 0xFF);\r           byte BitmapWidthByte2      = (byte)((IntBitmapWidth >> 8)   & 0xFF);\r           byte BitmapWidthByte3      = (byte)((IntBitmapWidth >> 16)  & 0xFF);\r           byte BitmapWidthByte4      = (byte)((IntBitmapWidth >> 24)  & 0xFF);\r           byte BitmapHeightByte1     = (byte)(IntBitmapHeight         & 0xFF);\r           byte BitmapHeightByte2     = (byte)((IntBitmapHeight >> 8)  & 0xFF);\r           byte BitmapHeightByte3     = (byte)((IntBitmapHeight >> 16) & 0xFF);\r           byte BitmapHeightByte4     = (byte)((IntBitmapHeight >> 24) & 0xFF);\r           byte BitmapImageSizeByte1  = (byte)(IntBitmapSize           & 0xFF);\r           byte BitmapImageSizeByte2  = (byte)((IntBitmapSize >> 8)    & 0xFF);\r           byte BitmapImageSizeByte3  = (byte)((IntBitmapSize >> 16)   & 0xFF);\r           byte BitmapImageSizeByte4  = (byte)((IntBitmapSize >> 24)   & 0xFF);\r\r          byte[] BitmapBodyHeader = new byte[] {\r                 InfoHeaderSizeByte1,        InfoHeaderSizeByte2,        InfoHeaderSizeByte3,        InfoHeaderSizeByte4,\r                       BitmapWidthByte1,           BitmapWidthByte2,           BitmapWidthByte3,           BitmapWidthByte4,\r                  BitmapHeightByte1,          BitmapHeightByte2,          BitmapHeightByte3,          BitmapHeightByte4,\r                 BitmapPlanesByte1,          BitmapPlanesByte2,\r                 BitmapBitCountByte1,        BitmapBitCountByte2,\r                       BitmapCompressionByte1,     BitmapCompressionByte2,     BitmapCompressionByte3,     BitmapCompressionByte4,\r                    BitmapImageSizeByte1,       BitmapImageSizeByte2,       BitmapImageSizeByte3,       BitmapImageSizeByte4,\r                      BitmapXPixelsPerMByte1,     BitmapXPixelsPerMByte2,     BitmapXPixelsPerMByte3,     BitmapXPixelsPerMByte4,\r                    BitmapYPixelsPerMByte1,     BitmapYPixelsPerMByte2,     BitmapYPixelsPerMByte3,     BitmapYPixelsPerMByte4,\r                    BitmapColorsUsedByte1,      BitmapColorsUsedByte2,      BitmapColorsUsedByte3,      BitmapColorsUsedByte4,\r                     BitmapColorsImportantByte1, BitmapColorsImportantByte2, BitmapColorsImportantByte3, BitmapColorsImportantByte4\r         };\r             fos.write(BitmapBodyHeader);\r\r          int bodySize = IntBitmapWidth * IntBitmapHeight;\r               int bitPad = 4 - ((IntBitmapWidth * 3) % 4);\r           if(bitPad == 4) { bitPad = 0; }\r                int countRow = 1;\r              int indexRow = bodySize - IntBitmapWidth;\r              int indexLastRow = indexRow;\r           byte[] rgbArray = new byte[3];\r\r                for(int i = 0; i < bodySize; i++)\r              {\r                      int colorValue = PixelMap[indexRow];\r                   rgbArray[0] = (byte)(colorValue         & 0xFF); // red\r                        rgbArray[1] = (byte)((colorValue >> 8)  & 0xFF); // green\r                      rgbArray[2] = (byte)((colorValue >> 16) & 0xFF); // blue\r                       fos.write(rgbArray);\r                   if(countRow == IntBitmapWidth)\r                 {\r                              // pad row to 4 bits requirement\r                               for(int p = 0; p < bitPad; p++)\r                                {\r                                      fos.write(0x00);\r                               }\r                              countRow = 1;\r                          indexRow = indexLastRow - IntBitmapWidth;\r                              indexLastRow = indexRow;\r                       }\r                      else\r                   {\r                              countRow++;\r                    }\r                      indexRow++;\r            }\r\r             fos.flush();\r           fos.close();\r*/\r        }\r\r     public static void main(String[] args)\r {\r              if(args.length < 3)\r            {\r                      System.out.println("USAGE : CMUScodec -action input output");\r          }\r              else\r           {\r                      if(args[0].equals("-t"))\r                       {\r                              try\r                            {\r                                      decode(args[1], args[2]);\r                              }\r                              catch(Exception e)\r                             {\r                                      System.out.println(e);\r                         }\r                      }\r                      else\r                   {\r                              System.out.println("action " + args[0] + "not yet supported");\r                 }\r              }\r      }\r\r}\r
\ No newline at end of file
diff --git a/ekit/com/hexidec/util/Cartesian.java b/ekit/com/hexidec/util/Cartesian.java
new file mode 100644 (file)
index 0000000..3a5444d
--- /dev/null
@@ -0,0 +1,137 @@
+package com.hexidec.util;
+
+public class Cartesian
+{
+       private int x;
+       private int y;
+
+       public Cartesian(int x, int y)
+       {
+               this.x = x;
+               this.y = y;
+       }
+
+       public Cartesian(Cartesian cartesian)
+       {
+               this.x = cartesian.getX();
+               this.y = cartesian.getY();
+       }
+
+       public Cartesian()
+       {
+               this(0, 0);
+       }
+
+       public int getX() { return x; }
+       public int getY() { return y; }
+
+       public void setX(int i) { x = i; }
+       public void setY(int i) { y = i; }
+
+       public void mirror(Cartesian cpSource)
+       {
+               this.setX(cpSource.getX());
+               this.setY(cpSource.getY());
+       }
+
+       public void add(Cartesian cpAdd)
+       {
+               this.setX(this.getX() + cpAdd.getX());
+               this.setY(this.getY() + cpAdd.getY());
+       }
+
+       public void subtract(Cartesian cpSub)
+       {
+               this.setX(this.getX() - cpSub.getX());
+               this.setY(this.getY() - cpSub.getY());
+       }
+
+       public void scale(int magnitude)
+       {
+               this.setX(this.getX() * magnitude);
+               this.setY(this.getY() * magnitude);
+       }
+
+       public Cartesian getScaledInstance(int magnitude)
+       {
+               Cartesian cpNew = this.dupe();
+               cpNew.scale(magnitude);
+               return cpNew;
+       }
+
+       public Cartesian getScaledInstance(Cartesian cpMagnitude)
+       {
+               Cartesian cpNew = this.dupe();
+               cpNew.setX(cpNew.getX() * cpMagnitude.getX());
+               cpNew.setY(cpNew.getY() * cpMagnitude.getY());
+               return cpNew;
+       }
+
+       public Cartesian addToLimit(Cartesian cpBase, Cartesian cpMin, Cartesian cpMax)
+       {
+               Cartesian cpNew = this.dupe();
+               cpNew.add(cpBase);
+               if(cpNew.getX() < cpMin.getX()) { cpNew.setX(cpMin.getX()); }
+               if(cpNew.getY() < cpMin.getY()) { cpNew.setY(cpMin.getY()); }
+               if(cpNew.getX() > cpMax.getX()) { cpNew.setX(cpMax.getX()); }
+               if(cpNew.getY() > cpMax.getY()) { cpNew.setY(cpMax.getY()); }
+               return cpNew;
+       }
+
+       public Cartesian translate(Cartesian cpOffset, boolean unknown)
+       {
+               Cartesian cpNew = this.dupe();
+               cpNew.add(cpOffset);
+               return cpNew;
+       }
+
+       public Cartesian translate(Cartesian cpOffset)
+       {
+               return translate(cpOffset, false);
+       }
+
+       public double distance(Cartesian cpTarget)
+       {
+               // Formula -> SQRT(SQR(x2 - x1) + SQR(y2 - y1))
+               int xDiff = cpTarget.getX() - this.getX();
+               int yDiff = cpTarget.getY() - this.getY();
+               return Math.sqrt((xDiff * xDiff) + (yDiff * yDiff));
+       }
+
+       public Cartesian midpoint(Cartesian cpTarget)
+       {
+               // Formula -> (x1 + x2) / 2, (y1 + y2) / 2
+               int xMid = (this.getX() + cpTarget.getX()) / 2;
+               int yMid = (this.getY() + cpTarget.getY()) / 2;
+               return new Cartesian(xMid, yMid);
+       }
+
+       public double slope(Cartesian cpTarget)
+       {
+               // Formula -> (y1 - y2) / (x1 - x2)
+               int xDiff = this.getX() - cpTarget.getX();
+               int yDiff = this.getY() - cpTarget.getY();
+               return yDiff / xDiff;
+       }
+
+       public Cartesian dupe()
+       {
+               return new Cartesian(this);
+       }
+
+       public boolean equals(Cartesian cpCompare)
+       {
+               return ((this.getX() == cpCompare.getX()) && (this.getY() == cpCompare.getY()));
+       }
+
+       public String toString()
+       {
+               return "(" + this.getX() + "," + this.getY() + ")";
+       }
+
+       public String toKey()
+       {
+               return "X" + this.getX() + "Y" + this.getY();
+       }
+
+}
\ No newline at end of file
diff --git a/ekit/com/hexidec/util/DMCScodec.java b/ekit/com/hexidec/util/DMCScodec.java
new file mode 100644 (file)
index 0000000..bf797f0
--- /dev/null
@@ -0,0 +1 @@
+/*\rGNU General Public License\r\rDMCScodec\rCopyright (C) 2002  Howard A Kistler\r\rThis program is free software; you can redistribute it and/or\rmodify it under the terms of the GNU General Public License\ras published by the Free Software Foundation; either version 2\rof the License, or (at your option) any later version.\r\rThis program is distributed in the hope that it will be useful,\rbut WITHOUT ANY WARRANTY; without even the implied warranty of\rMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\rGNU General Public License for more details.\r\rYou should have received a copy of the GNU General Public License\ralong with this program; if not, write to the Free Software\rFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\r*/\r\rpackage com.hexidec.util;\r\rimport java.awt.AWTException;\rimport java.io.File;\rimport java.io.FileInputStream;\rimport java.io.FileNotFoundException;\rimport java.io.FileOutputStream;\rimport java.io.FileWriter;\rimport java.io.IOException;\r\r/** DMCScodec\r  *\r  * Utility for reading (and eventually converting) Deluxe Music\r  * Construction Set (DMCS) files\r  *\r  * @author Howard Kistler\r  * @version 0.1\r  *\r  * VERSION HISTORY\r  * 0.1 (03/13/2002) - initial creation (03/13/2002)\r  */\r\rpublic class DMCScodec\r{\r\r//  Constants ---------------------------------------------------------------------------->\r\r/*\r       DMCS File Structure\r\r   FILE HEADER\r    ====================\r   (At the beginning of each file)\r        FILE HEADER BLOCK\r              4 bytes - FORM\r         4 bytes - ?\r            4 bytes - DMCS\r         4 bytes - AMGA (for Amiga files)\r               4 bytes - ? (all zeroes?)\r      SC HEADER BLOCK\r                4 bytes - USC1\r         8 bytes - ?\r            4 bytes - ?\r            8 bytes - ?\r            4 x 32 bytes - ?\r               1 byte - Title Byte count (number of letters in song title)\r            X bytes - Song Title (length stated in previous byte)\r          16 bytes - 00 05 FE 77 01 01 01 02 00 00 3F 80 00 7F 00 00\r\r    SONG BODY\r      ====================\r   UBR1 BLOCKS\r            4 bytes - UBR1\r\r        INSTRUMENT BLOCK\r       ====================\r   (At the end of each file)\r      INSTRUMENT HEAD BLOCK\r          4 bytes - UVLT\r         22 bytes -  00 00 00 12 00 00 00 0A 00 13 00 1F 00 2F 00 3F 00 51 00 69 00 7F\r  INDIVIDUAL INSTRUMENT BLOCKS\r           4 bytes - UIID\r         4 bytes - ? (small int)\r                X bytes - Instrument Name\r              2 bytes - 00 00 (last instrument may have just one byte of 00)\r*/\r\r     // Header Array Sizes\r  private final static byte StartFileHeaderSize = (byte)20;\r      private final static byte InfoHeaderSize = (byte)40; // InfoHeader is always 40 bytes in size for BMP/ICO/CUR format\r\r  // File Header Fields\r  private final static byte[] FileHeaderFormWord = { 'F', 'O', 'R', 'M', };\r      private       static byte[] FileHeaderSizeWord = new byte[4];\r  private final static byte[] FileHeaderTypeWord = { 'D', 'M', 'C', 'S' };\r       private final static byte[] FileHeaderOSAMWord = { 'A', 'M', 'G', 'A' }; // OS Word for Amiga DMCS files\r       private final static byte[] FileHeaderTailWord = { (byte)0, (byte)0, (byte)0, (byte)0 };\r\r      // Song Body Fields\r    private final static byte[] SongBlockUnitWord = { 'U', 'B', 'R', '1' };\r\r       // Instrument Body Fields\r      private final static byte[] InstrumentBlockHeadWord = { 'U', 'V', 'L', 'T' };\r  private final static byte[] InstrumentBlockUnitWord = { 'U', 'I', 'I', 'D' };\r\r//  Public Vartypes ---------------------------------------------------------------------->\r\r    public final static int FILETYPE_DMCS   = 1;\r   public final static int FILETYPE_TEXT   = 2;\r   public final static int FILETYPE_FINALE = 3;\r\r//  Constructor -------------------------------------------------------------------------->\r\r     public DMCScodec()\r     {\r      }\r\r//  Decode Method ------------------------------------------------------------------------>\r\r        public static void decode(String sourceFile, String destFile)\r  throws FileNotFoundException, IOException, AWTException\r        {\r              convertToTextFile(sourceFile, destFile);\r       }\r\r//  Encode Method ------------------------------------------------------------------------>\r\r        public static void encode(String sourceFile, String destFile, int fileType)\r    throws FileNotFoundException, IOException, AWTException\r        {\r//            String newFormat = convertToFormat(sourceFile, fileType);\r//            writeToDMCSFile(newFormat, destFile);\r  }\r\r//  DMCS-to-TEXT File Conversion -------------------------------------------------------->\r\r protected static void convertToTextFile(String inFile, String outFile)\r throws IOException\r     {\r              File srcFile = new File(inFile);\r               FileInputStream fis = new FileInputStream(srcFile);\r            int filesize = (int)(srcFile.length());\r                byte[] bData = new byte[filesize];\r             int iCounter = 0;\r              while(iCounter < filesize)\r             {\r                      bData[iCounter] = (byte)(fis.read());\r                  iCounter++;\r            }\r              fis.close();\r\r          FileWriter fw = new FileWriter(new File(outFile));\r\r            String sOutput = "FILE SIZE  : " + srcFile.length() + "\r";\r            fw.write(sOutput, 0, sOutput.length());\r\r               sOutput = "BYTES READ : " + iCounter + "\r";\r           fw.write(sOutput, 0, sOutput.length());\r\r               int iPlace = 0;\r\r               sOutput = "====================\rFILE HEADER\r====================\r";\r         fw.write(sOutput, 0, sOutput.length());\r\r               sOutput = "--------------------\rFILE HEADER BLOCK\r--------------------\r";\r           fw.write(sOutput, 0, sOutput.length());\r\r               sOutput = "FORM BLOCK : " + (char)(bData[iPlace++]) + (char)(bData[iPlace++]) + (char)(bData[iPlace++]) + (char)(bData[iPlace++]) + "\r";\r              fw.write(sOutput, 0, sOutput.length());\r\r               int iSize =\r                    (int)(\r                         ((bData[iPlace++]) << 24) +\r                            ((bData[iPlace++]) << 16) +\r                            ((bData[iPlace++]) <<  8) +\r                            ((bData[iPlace++])      )\r                              );\r             sOutput = "SIZE BLOCK : " + iSize + "\r";\r              fw.write(sOutput, 0, sOutput.length());\r\r               sOutput = "TYPE BLOCK : " + (char)(bData[iPlace++]) + (char)(bData[iPlace++]) + (char)(bData[iPlace++]) + (char)(bData[iPlace++]) + "\r";\r              fw.write(sOutput, 0, sOutput.length());\r\r               sOutput = "OS BLOCK   : " + (char)(bData[iPlace++]) + (char)(bData[iPlace++]) + (char)(bData[iPlace++]) + (char)(bData[iPlace++]) + "\r";\r              fw.write(sOutput, 0, sOutput.length());\r\r               sOutput = "TAIL BLOCK : " + (char)(bData[iPlace++]) + (char)(bData[iPlace++]) + (char)(bData[iPlace++]) + (char)(bData[iPlace++]) + "\r";\r              fw.write(sOutput, 0, sOutput.length());\r\r               sOutput = "--------------------\rSC HEADER BLOCK\r--------------------\r";\r             fw.write(sOutput, 0, sOutput.length());\r\r               sOutput = "USC1 BLOCK : " + (char)(bData[iPlace++]) + (char)(bData[iPlace++]) + (char)(bData[iPlace++]) + (char)(bData[iPlace++]) + "\r";\r              fw.write(sOutput, 0, sOutput.length());\r\r               int iData =\r                    (int)(\r                         ((bData[iPlace++]) << 24) +\r                            ((bData[iPlace++]) << 16) +\r                            ((bData[iPlace++]) <<  8) +\r                            ((bData[iPlace++])      )\r                              );\r             sOutput = "DATA INT 1 : " + iData + "\r";\r              fw.write(sOutput, 0, sOutput.length());\r\r               iData =\r                        (int)(\r                         ((bData[iPlace++]) << 24) +\r                            ((bData[iPlace++]) << 16) +\r                            ((bData[iPlace++]) <<  8) +\r                            ((bData[iPlace++])      )\r                              );\r             sOutput = "DATA INT 2 : " + iData + "\r";\r              fw.write(sOutput, 0, sOutput.length());\r\r               iData =\r                        (int)(\r                         ((bData[iPlace++]) << 24) +\r                            ((bData[iPlace++]) << 16) +\r                            ((bData[iPlace++]) <<  8) +\r                            ((bData[iPlace++])      )\r                              );\r             sOutput = "DATA INT 3 : " + iData + "\r";\r              fw.write(sOutput, 0, sOutput.length());\r\r               iData =\r                        (int)(\r                         ((bData[iPlace++]) << 24) +\r                            ((bData[iPlace++]) << 16) +\r                            ((bData[iPlace++]) <<  8) +\r                            ((bData[iPlace++])      )\r                              );\r             sOutput = "DATA INT 4 : " + iData + "\r";\r              fw.write(sOutput, 0, sOutput.length());\r\r               iData =\r                        (int)(\r                         ((bData[iPlace++]) << 24) +\r                            ((bData[iPlace++]) << 16) +\r                            ((bData[iPlace++]) <<  8) +\r                            ((bData[iPlace++])      )\r                              );\r             sOutput = "DATA INT 5 : " + iData + "\r";\r              fw.write(sOutput, 0, sOutput.length());\r\r               for(int i = 0; i < 32; i++)\r            {\r                      iData =\r                                (int)(\r                                 ((bData[iPlace++]) << 24) +\r                                    ((bData[iPlace++]) << 16) +\r                                    ((bData[iPlace++]) <<  8) +\r                                    ((bData[iPlace++])      )\r                                      );\r                     sOutput = "SUB INT " + (i+1) + " : " + iData + "\r";\r                   fw.write(sOutput, 0, sOutput.length());\r                }\r\r             sOutput = "PAD BYTES  : " + bData[iPlace++] + bData[iPlace++] + bData[iPlace++] + bData[iPlace++] + "\r";\r              fw.write(sOutput, 0, sOutput.length());\r\r               int titleCharCount = (int)(bData[iPlace++]);\r           sOutput = "TITLE BYTE : " + titleCharCount  + "\r";\r            fw.write(sOutput, 0, sOutput.length());\r\r               sOutput = "SONG TITLE : ";\r             for(int i = 0; i < titleCharCount; i++)\r                {\r                      sOutput = sOutput + (char)(bData[iPlace++]);\r           }\r              sOutput = sOutput + "\r";\r              fw.write(sOutput, 0, sOutput.length());\r\r               for(int i = 0; i < 19; i++)\r            {\r                      sOutput = "POST BYTE " + (i+1) + " : " + bData[iPlace++] + "\r";\r                       fw.write(sOutput, 0, sOutput.length());\r                }\r\r             sOutput = "====================\rSONG BODY\r====================\r";\r           fw.write(sOutput, 0, sOutput.length());\r\r               byte byteA = (byte)0;\r          byte byteB = (byte)0;\r          String blockWord = "";\r         while(iPlace < filesize - 5)\r           {\r                      byteA = bData[iPlace++];\r                       byteB = bData[iPlace++];\r                       blockWord = "" + (char)byteA + (char)byteB;\r                    if(blockWord.equals("UB"))\r                     {\r                              byte byteC = bData[iPlace++];\r                          byte byteD = bData[iPlace++];\r                          String blockWord2 = "" + (char)byteC + (char)byteD;\r                            if(blockWord2.equals("R1"))\r                            {\r                                      sOutput = "--------------------\rUBR1 DATA BLOCK\r--------------------\r";\r                                     fw.write(sOutput, 0, sOutput.length());\r\r                                       sOutput = "DATA HEAD  : " + blockWord + blockWord2 + "\r";\r                                     fw.write(sOutput, 0, sOutput.length());\r                                }\r                              else\r                           {\r                                      int iWord =\r                                            (int)(\r                                                 (byteA <<  8) +\r                                                        (byteB      )\r                                                  );\r                                     sOutput = "WORD VALUE : " + iWord + "\r";\r                                      fw.write(sOutput, 0, sOutput.length());\r                                        iWord =\r                                                (int)(\r                                                 (byteC <<  8) +\r                                                        (byteD      )\r                                                  );\r                                     sOutput = "WORD VALUE : " + iWord + "\r";\r                                      fw.write(sOutput, 0, sOutput.length());\r                                }\r                      }\r                      else if(blockWord.equals("UV"))\r                        {\r                              byte byteC = bData[iPlace++];\r                          byte byteD = bData[iPlace++];\r                          String blockWord2 = "" + (char)byteC + (char)byteD;\r                            if(blockWord2.equals("LT"))\r                            {\r                                      sOutput = "====================\rINSTRUMENT BLOCK\r====================\r";\r                                    fw.write(sOutput, 0, sOutput.length());\r        \r                                       sOutput = "--------------------\rINSTRUMENT HEAD BLOCK\r--------------------\r";\r                                       fw.write(sOutput, 0, sOutput.length());\r        \r                                       sOutput = "GROUP HEAD : " + blockWord + blockWord2 + "\r";\r                                     fw.write(sOutput, 0, sOutput.length());\r\r                                       int iWord = 0;\r                                 for(int i = 0; i < 11; i++)\r                                    {\r                                              iWord =\r                                                        (int)(\r                                                         ((bData[iPlace++]) <<  8) +\r                                                            ((bData[iPlace++])      )\r                                                              );\r                                             sOutput = "SUB WORD " + (i+1) + " : " + iWord + "\r";\r                                          fw.write(sOutput, 0, sOutput.length());\r                                        }\r                              }\r                              else\r                           {\r                                      int iWord =\r                                            (int)(\r                                                 (byteA <<  8) +\r                                                        (byteB      )\r                                                  );\r                                     sOutput = "WORD VALUE : " + iWord + "\r";\r                                      fw.write(sOutput, 0, sOutput.length());\r                                        iWord =\r                                                (int)(\r                                                 (byteC <<  8) +\r                                                        (byteD      )\r                                                  );\r                                     sOutput = "WORD VALUE : " + iWord + "\r";\r                                      fw.write(sOutput, 0, sOutput.length());\r                                }\r                      }\r                      else if(blockWord.equals("UI"))\r                        {\r                              byte byteC = bData[iPlace++];\r                          byte byteD = bData[iPlace++];\r                          String blockWord2 = "" + (char)byteC + (char)byteD;\r                            if(blockWord2.equals("ID"))\r                            {\r                                      sOutput = "--------------------\rINDIVIDUAL INSTRUMENT BLOCK\r--------------------\r";\r                                 fw.write(sOutput, 0, sOutput.length());\r\r                                       sOutput = "INSTR HEAD : " + blockWord + blockWord2 + "\r";\r                                     fw.write(sOutput, 0, sOutput.length());\r\r                                       int iVal =\r                                             (int)(\r                                                 ((bData[iPlace++]) << 24) +\r                                                    ((bData[iPlace++]) << 16) +\r                                                    ((bData[iPlace++]) <<  8) +\r                                                    ((bData[iPlace++])      )\r                                                      );\r                                     sOutput = "NAME BYTES : " + iVal + "\r";\r                                       fw.write(sOutput, 0, sOutput.length());\r\r                                       sOutput = "INSTR NAME : ";\r                                     for(int i = 0; i < iVal - 1; i++)\r                                      {\r                                              sOutput = sOutput + (char)(bData[iPlace++]);\r                                   }\r                                      sOutput = sOutput + "\r";\r                                      fw.write(sOutput, 0, sOutput.length());\r\r                                       if(iPlace < filesize - 2)\r                                      {\r                                              sOutput = "PAD BYTES  : " + bData[iPlace++] + bData[iPlace++] + "\r";\r                                          fw.write(sOutput, 0, sOutput.length());\r                                        }\r                              }\r                              else\r                           {\r                                      int iWord =\r                                            (int)(\r                                                 (byteA <<  8) +\r                                                        (byteB      )\r                                                  );\r                                     sOutput = "WORD VALUE : " + iWord + "\r";\r                                      fw.write(sOutput, 0, sOutput.length());\r                                        iWord =\r                                                (int)(\r                                                 (byteC <<  8) +\r                                                        (byteD      )\r                                                  );\r                                     sOutput = "WORD VALUE : " + iWord + "\r";\r                                      fw.write(sOutput, 0, sOutput.length());\r                                }\r                      }\r                      else {\r                         int iWord =\r                                    (int)(\r                                         (byteA <<  8) +\r                                                (byteB      )\r                                          );\r                             sOutput = "WORD VALUE : " + iWord + "\r";\r                              fw.write(sOutput, 0, sOutput.length());\r                        }\r              }\r\r             fw.flush();\r            fw.close();\r    }\r\r//  File Write Method ------------------------------------------------------------------->\r\r protected static void writeToDMCSFile(String fileData, String outFile)\r throws IOException\r     {\r              FileOutputStream fos = new FileOutputStream(new File(outFile));\r\r               byte FileSizeByte1 = (byte)(fileData.length()         & 0xFF);\r         byte FileSizeByte2 = (byte)((fileData.length() >> 8)  & 0xFF);\r         byte FileSizeByte3 = (byte)((fileData.length() >> 16) & 0xFF);\r         byte FileSizeByte4 = (byte)((fileData.length() >> 24) & 0xFF);\r\r                byte[] DMCSFileHeader = new byte[]\r             {\r                      FileHeaderFormWord[0], FileHeaderFormWord[1], FileHeaderFormWord[2], FileHeaderFormWord[3],\r                    FileSizeByte1,         FileSizeByte2,         FileSizeByte3,         FileSizeByte4,\r                    FileHeaderTypeWord[0], FileHeaderTypeWord[1], FileHeaderTypeWord[2], FileHeaderTypeWord[3],\r                    FileHeaderOSAMWord[0], FileHeaderOSAMWord[1], FileHeaderOSAMWord[2], FileHeaderOSAMWord[3],\r                    FileHeaderTailWord[0], FileHeaderTailWord[1], FileHeaderTailWord[2], FileHeaderTailWord[3]\r             };\r             fos.write(DMCSFileHeader);\r\r/*\r         byte BitmapWidthByte1      = (byte)(IntBitmapWidth          & 0xFF);\r           byte BitmapWidthByte2      = (byte)((IntBitmapWidth >> 8)   & 0xFF);\r           byte BitmapWidthByte3      = (byte)((IntBitmapWidth >> 16)  & 0xFF);\r           byte BitmapWidthByte4      = (byte)((IntBitmapWidth >> 24)  & 0xFF);\r           byte BitmapHeightByte1     = (byte)(IntBitmapHeight         & 0xFF);\r           byte BitmapHeightByte2     = (byte)((IntBitmapHeight >> 8)  & 0xFF);\r           byte BitmapHeightByte3     = (byte)((IntBitmapHeight >> 16) & 0xFF);\r           byte BitmapHeightByte4     = (byte)((IntBitmapHeight >> 24) & 0xFF);\r           byte BitmapImageSizeByte1  = (byte)(IntBitmapSize           & 0xFF);\r           byte BitmapImageSizeByte2  = (byte)((IntBitmapSize >> 8)    & 0xFF);\r           byte BitmapImageSizeByte3  = (byte)((IntBitmapSize >> 16)   & 0xFF);\r           byte BitmapImageSizeByte4  = (byte)((IntBitmapSize >> 24)   & 0xFF);\r\r          byte[] BitmapBodyHeader = new byte[] {\r                 InfoHeaderSizeByte1,        InfoHeaderSizeByte2,        InfoHeaderSizeByte3,        InfoHeaderSizeByte4,\r                       BitmapWidthByte1,           BitmapWidthByte2,           BitmapWidthByte3,           BitmapWidthByte4,\r                  BitmapHeightByte1,          BitmapHeightByte2,          BitmapHeightByte3,          BitmapHeightByte4,\r                 BitmapPlanesByte1,          BitmapPlanesByte2,\r                 BitmapBitCountByte1,        BitmapBitCountByte2,\r                       BitmapCompressionByte1,     BitmapCompressionByte2,     BitmapCompressionByte3,     BitmapCompressionByte4,\r                    BitmapImageSizeByte1,       BitmapImageSizeByte2,       BitmapImageSizeByte3,       BitmapImageSizeByte4,\r                      BitmapXPixelsPerMByte1,     BitmapXPixelsPerMByte2,     BitmapXPixelsPerMByte3,     BitmapXPixelsPerMByte4,\r                    BitmapYPixelsPerMByte1,     BitmapYPixelsPerMByte2,     BitmapYPixelsPerMByte3,     BitmapYPixelsPerMByte4,\r                    BitmapColorsUsedByte1,      BitmapColorsUsedByte2,      BitmapColorsUsedByte3,      BitmapColorsUsedByte4,\r                     BitmapColorsImportantByte1, BitmapColorsImportantByte2, BitmapColorsImportantByte3, BitmapColorsImportantByte4\r         };\r             fos.write(BitmapBodyHeader);\r\r          int bodySize = IntBitmapWidth * IntBitmapHeight;\r               int bitPad = 4 - ((IntBitmapWidth * 3) % 4);\r           if(bitPad == 4) { bitPad = 0; }\r                int countRow = 1;\r              int indexRow = bodySize - IntBitmapWidth;\r              int indexLastRow = indexRow;\r           byte[] rgbArray = new byte[3];\r\r                for(int i = 0; i < bodySize; i++)\r              {\r                      int colorValue = PixelMap[indexRow];\r                   rgbArray[0] = (byte)(colorValue         & 0xFF); // red\r                        rgbArray[1] = (byte)((colorValue >> 8)  & 0xFF); // green\r                      rgbArray[2] = (byte)((colorValue >> 16) & 0xFF); // blue\r                       fos.write(rgbArray);\r                   if(countRow == IntBitmapWidth)\r                 {\r                              // pad row to 4 bits requirement\r                               for(int p = 0; p < bitPad; p++)\r                                {\r                                      fos.write(0x00);\r                               }\r                              countRow = 1;\r                          indexRow = indexLastRow - IntBitmapWidth;\r                              indexLastRow = indexRow;\r                       }\r                      else\r                   {\r                              countRow++;\r                    }\r                      indexRow++;\r            }\r*/\r\r          fos.flush();\r           fos.close();\r   }\r\r     public static void main(String[] args)\r {\r              if(args.length < 3)\r            {\r                      System.out.println("USAGE : DMCScodec -action input output");\r          }\r              else\r           {\r                      if(args[0].equals("-t"))\r                       {\r                              try\r                            {\r                                      decode(args[1], args[2]);\r                              }\r                              catch(Exception e)\r                             {\r                                      System.out.println(e);\r                         }\r                      }\r                      else\r                   {\r                              System.out.println("action " + args[0] + "not yet supported");\r                 }\r              }\r      }\r\r}\r
\ No newline at end of file
diff --git a/ekit/com/hexidec/util/MutableFilter.java b/ekit/com/hexidec/util/MutableFilter.java
new file mode 100644 (file)
index 0000000..bbeb3fc
--- /dev/null
@@ -0,0 +1,77 @@
+/*\r
+GNU Lesser General Public License\r
+\r
+MutableFilter\r
+Copyright (C) 2000-2002  Howard A Kistler\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+*/\r
+\r
+package com.hexidec.util;\r
+\r
+import java.io.File;\r
+import javax.swing.filechooser.FileFilter;\r
+\r
+/** Class for providing JFileChooser with a FileFilter\r
+  */\r
+public class MutableFilter extends FileFilter\r
+{\r
+       private String[] acceptableExtensions;\r
+       private String descriptor;\r
+\r
+       public MutableFilter(String[] exts, String desc)\r
+       {\r
+               acceptableExtensions = exts;\r
+               StringBuffer strbDesc = new StringBuffer(desc + " (");\r
+               for(int i = 0; i < acceptableExtensions.length; i++)\r
+               {\r
+                       if(i > 0) { strbDesc.append(", "); }\r
+                       strbDesc.append("*." + acceptableExtensions[i]);\r
+               }\r
+               strbDesc.append(")");\r
+               descriptor = strbDesc.toString();\r
+       }\r
+\r
+       public boolean accept(File file)\r
+       {\r
+               if(file.isDirectory())\r
+               {\r
+                       return true;\r
+               }\r
+               String fileName = file.getName();\r
+               String fileExt = fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length()).toLowerCase();\r
+               if(fileExt != null)\r
+               {\r
+                       for(int i = 0; i < acceptableExtensions.length; i++)\r
+                       {\r
+                               if(fileExt.equals(acceptableExtensions[i]))\r
+                               {\r
+                                       return true;\r
+                               }\r
+                       }\r
+                       return false;\r
+               }\r
+               else\r
+               {\r
+                       return false;\r
+               }\r
+       }\r
+\r
+       public String getDescription()\r
+       {\r
+               return descriptor;\r
+       }\r
+}\r
+\r
diff --git a/ekit/com/hexidec/util/PatternReplacer.java b/ekit/com/hexidec/util/PatternReplacer.java
new file mode 100644 (file)
index 0000000..3fadfb0
--- /dev/null
@@ -0,0 +1,78 @@
+package com.hexidec.util;\r
+\r
+/*\r
+GNU General Public License\r
+\r
+PatternReplacer - Simple Pattern Replacement Class\r
+Copyright (C) 2001  Howard A Kistler\r
+\r
+This program is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU General Public License\r
+as published by the Free Software Foundation; either version 2\r
+of the License, or (at your option) any later version.\r
+\r
+This program is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+GNU General Public License for more details.\r
+\r
+You should have received a copy of the GNU General Public License\r
+along with this program; if not, write to the Free Software\r
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\r
+*/\r
+\r
+import java.util.Hashtable;\r
+\r
+/** PatternReplacer\r
+  * Utility class for replacing patterns in script strings\r
+  *\r
+  * @author Howard Kistler\r
+  * @version 0.2\r
+  *\r
+  * VERSION HISTORY\r
+  * 0.1 (04/04/2001) - initial creation (04/04/2001)\r
+  * 0.2 (04/09/2001) - separation into own class (04/09/2001)\r
+  */\r
+\r
+public class PatternReplacer {\r
+\r
+       private Hashtable patternTable;\r
+\r
+       public PatternReplacer(Hashtable patterns) {\r
+               patternTable = patterns;\r
+       }\r
+\r
+       public PatternReplacer() {\r
+               patternTable = new Hashtable();\r
+       }\r
+\r
+       public void addPattern(String pattern, String replacement) {\r
+               if(patternTable.containsKey(pattern)) {\r
+                       patternTable.remove(pattern);\r
+               }\r
+               patternTable.put(pattern, replacement);\r
+       }\r
+\r
+       public void removePattern(String pattern) {\r
+               if(patternTable.containsKey(pattern)) {\r
+                       patternTable.remove(pattern);\r
+               }\r
+       }\r
+\r
+       public String getPattern(String pattern) {\r
+               if(patternTable.containsKey(pattern)) {\r
+                       return (String)(patternTable.get(pattern));\r
+               }\r
+               return null;\r
+       }\r
+\r
+       public void clearPatterns() {\r
+               patternTable.clear();\r
+       }\r
+\r
+       public int patternCount() {\r
+               return patternTable.size();\r
+       }\r
+\r
+}\r
+\r
diff --git a/ekit/com/hexidec/util/Translatrix.java b/ekit/com/hexidec/util/Translatrix.java
new file mode 100644 (file)
index 0000000..a428d4e
--- /dev/null
@@ -0,0 +1,111 @@
+/*\r
+GNU Lesser General Public License\r
+\r
+Translatrix - General Access To Language Resource Bundles\r
+Copyright (C) 2002  Howard A Kistler\r
+\r
+This library is free software; you can redistribute it and/or\r
+modify it under the terms of the GNU Lesser General Public\r
+License as published by the Free Software Foundation; either\r
+version 2.1 of the License, or (at your option) any later version.\r
+\r
+This library is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+Lesser General Public License for more details.\r
+\r
+You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+*/\r
+\r
+package com.hexidec.util;\r
+\r
+import java.util.Locale;\r
+import java.util.MissingResourceException;\r
+import java.util.ResourceBundle;\r
+\r
+public class Translatrix\r
+{\r
+       private static ResourceBundle langResources;\r
+       private static String bundleName;\r
+\r
+       public Translatrix(String bundle)\r
+       {\r
+               bundleName = bundle;\r
+               try\r
+               {\r
+                       langResources = ResourceBundle.getBundle(bundleName);\r
+               }\r
+               catch(MissingResourceException mre)\r
+               {\r
+                       logException("MissingResourceException while loading language file", mre);\r
+               }\r
+       }\r
+\r
+       public static void setBundleName(String bundle)\r
+       {\r
+               bundleName = bundle;\r
+       }\r
+\r
+       public static void setLocale(Locale locale)\r
+       {\r
+               if(bundleName == null)\r
+               {\r
+                       return;\r
+               }\r
+               if(locale != null)\r
+               {\r
+                       try\r
+                       {\r
+                               langResources = ResourceBundle.getBundle(bundleName, locale);\r
+                       }\r
+                       catch(MissingResourceException mre1)\r
+                       {\r
+                               try\r
+                               {\r
+                                       langResources = ResourceBundle.getBundle(bundleName);\r
+                               }\r
+                               catch(MissingResourceException mre2)\r
+                               {\r
+                                       logException("MissingResourceException while loading language file", mre2);\r
+                               }\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       try\r
+                       {\r
+                               langResources = ResourceBundle.getBundle(bundleName);\r
+                       }\r
+                       catch(MissingResourceException mre)\r
+                       {\r
+                               logException("MissingResourceException while loading language file", mre);\r
+                       }\r
+               }\r
+       }\r
+\r
+       public static void setLocale(String sLanguage, String sCountry)\r
+       {\r
+               if(sLanguage != null && sCountry != null)\r
+               {\r
+                       setLocale(new Locale(sLanguage, sCountry));\r
+               }\r
+       }\r
+\r
+       public static String getTranslationString(String originalText)\r
+       {\r
+               if(bundleName == null)\r
+               {\r
+                       return originalText;\r
+               }\r
+               return langResources.getString(originalText);\r
+       }\r
+\r
+       private static void logException(String internalMessage, Exception e)\r
+       {\r
+               System.err.println(internalMessage);\r
+               e.printStackTrace(System.err);\r
+       }\r
+\r
+}
\ No newline at end of file
diff --git a/ekit/com/hexidec/util/TreeSpider$FileTreeComparator.class b/ekit/com/hexidec/util/TreeSpider$FileTreeComparator.class
new file mode 100644 (file)
index 0000000..473353b
Binary files /dev/null and b/ekit/com/hexidec/util/TreeSpider$FileTreeComparator.class differ
diff --git a/ekit/com/hexidec/util/TreeSpider.class b/ekit/com/hexidec/util/TreeSpider.class
new file mode 100644 (file)
index 0000000..d2d873c
Binary files /dev/null and b/ekit/com/hexidec/util/TreeSpider.class differ
diff --git a/ekit/com/hexidec/util/TreeSpider.java b/ekit/com/hexidec/util/TreeSpider.java
new file mode 100644 (file)
index 0000000..b738860
--- /dev/null
@@ -0,0 +1 @@
+/*\rGNU General Public License\r\rTreeSpider - Directory & File Traversal Utility Class\rCopyright (C) 2000  Howard A Kistler\r\rThis program is free software; you can redistribute it and/or\rmodify it under the terms of the GNU General Public License\ras published by the Free Software Foundation; either version 2\rof the License, or (at your option) any later version.\r\rThis program is distributed in the hope that it will be useful,\rbut WITHOUT ANY WARRANTY; without even the implied warranty of\rMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\rGNU General Public License for more details.\r\rYou should have received a copy of the GNU General Public License\ralong with this program; if not, write to the Free Software\rFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\r*/\r\rpackage com.hexidec.util;\r\rimport java.io.File;\rimport java.util.Arrays;\rimport java.util.Collections;\rimport java.util.Comparator;\rimport java.util.Enumeration;\rimport java.util.Hashtable;\rimport java.util.Vector;\rimport javax.swing.tree.DefaultMutableTreeNode;\rimport javax.swing.tree.DefaultTreeModel;\r\r/** TreeSpider\r  * Utility class for traversing, scanning & describing directory/file structures\r  *\r  * @author Howard Kistler\r  * @version 0.2\r  *\r  * VERSION HISTORY\r  * 0.1 (09/14/2000) - initial creation (started on 08/09/2000)\r  * 0.2 (09/22/2001) - numerous enhancements\r  */\r\rpublic class TreeSpider {\r\r private File rootFile;\r private Vector vcFiles;\r        private Vector vcExtensions;\r   private int maxDepth;\r  private boolean bScreenExtensions;\r     private boolean bFileNamesOnly;\r        private boolean bDisplayMode;\r  private FileTreeComparator localComparison;\r\r//  Constructors ---------------------------------------------------------------------------->\r\r   /* Main Constructor */\r public TreeSpider(String origin, Vector exts, boolean caseSensitive, int mDepth) {\r             rootFile = new File(origin);\r           vcFiles = new Vector();\r                vcExtensions = exts;\r           maxDepth = mDepth;\r             bScreenExtensions = false;\r             bFileNamesOnly = false;\r                bDisplayMode = false;\r          if(vcExtensions.size() > 0) {\r                  bScreenExtensions = true;\r              }\r              localComparison = new FileTreeComparator(caseSensitive);\r       }\r\r     /* Alternate Constructor */\r    public TreeSpider(String origin, Vector exts, boolean caseSensitive) {\r         this(origin, new Vector(), caseSensitive, 0);\r  }\r\r     /* Alternate Constructor */\r    public TreeSpider(String origin, boolean caseSensitive, int mDepth) {\r          this(origin, new Vector(), caseSensitive, mDepth);\r     }\r\r     /* Alternate Constructor */\r    public TreeSpider(String origin, boolean caseSensitive) {\r              this(origin, new Vector(), caseSensitive, 0);\r  }\r\r     /* Alternate Constructor */\r    public TreeSpider(String origin, int mDepth) {\r         this(origin, new Vector(), false, mDepth);\r     }\r\r     /* Alternate Constructor */\r    public TreeSpider(String origin) {\r             this(origin, new Vector(), false, 0);\r  }\r\r     /* Alternate Constructor */\r    public TreeSpider() {\r          this(".", new Vector(), false, 0);\r     }\r\r//  Public Class Methods -------------------------------------------------------------------->\r\r     /** Returns a DefaultTreeModel built from the specified root file */\r   public DefaultTreeModel fetchTree(File newRootFile) {\r          return describeTree(newRootFile);\r      }\r\r     /** Returns a DefaultTreeModel built from the preset root file */\r      public DefaultTreeModel fetchTree() {\r          return describeTree(rootFile);\r }\r\r     /** Returns an unsorted listing of the file tree */\r    public Vector fetchMassListing() {\r             return fetchListing();\r }\r\r     /** Returns an index-style listing of the file tree of complete file names and paths */\r        public Vector sortMassListing() {\r              Vector vcListing = fetchListing();\r             Collections.sort(vcListing, localComparison);\r          return vcListing;\r      }\r\r     /** Returns an index-style listing of the file tree of file names only */\r      public Vector sortFileListing() {\r              Vector vcListing = trimToName(fetchListing());\r         Collections.sort(vcListing, localComparison);\r          return vcListing;\r      }\r\r     /** Returns a directory-style listing of the file tree */\r      public Hashtable collectListing() {\r            Vector vcListing = fetchListing();\r             Hashtable htCollected = new Hashtable();\r               for(int i = 0; i < vcListing.size(); i++) {\r                    String fullname = (String)(vcListing.elementAt(i));\r                    String filepath = fullname.substring(0, fullname.lastIndexOf(File.separator));\r                 String filename = fullname.substring(fullname.lastIndexOf(File.separator) + 1, fullname.length());\r                     if(htCollected.containsKey(filepath)) {\r                                ((Vector)(htCollected.get(filepath))).add(filename);\r                   }\r                      else {\r                         htCollected.put(filepath, new Vector());\r                               ((Vector)(htCollected.get(filepath))).add(filename);\r                   }\r              }\r              return htCollected;\r    }\r\r//  Internal Class Methods ------------------------------------------------------------------>\r\r     private DefaultTreeModel describeTree(File rootFile) {\r         DefaultMutableTreeNode treeRoot = new DefaultMutableTreeNode(rootFile.getName());\r              DefaultTreeModel treeModel = new DefaultTreeModel(treeRoot);\r           if(!(rootFile.isDirectory())) {\r                        return treeModel;\r              }\r              String rootStr = rootFile.getAbsolutePath().trim() + File.separator;\r           Vector vcContents = fetchListing();\r            while(vcContents.size() > 0) {\r                 String nodeName = (String)(vcContents.elementAt(0));\r                   if(nodeName.startsWith(rootStr)) {\r                             nodeName = nodeName.substring(rootStr.length());\r                               if(nodeName.indexOf(File.separator) > -1) {\r                                    String baseNode = nodeName.substring(0, nodeName.indexOf(File.separator));\r                                     describeTreeSubNodes(vcContents, treeModel, treeRoot, rootStr, baseNode);\r                              }\r                              else {\r                                 treeModel.insertNodeInto(new DefaultMutableTreeNode(nodeName), treeRoot, treeModel.getChildCount(treeRoot));\r                                   vcContents.removeElementAt(0);\r                         }\r                      }\r                      else {\r                         vcContents.removeElementAt(0);\r                 }\r              }\r              return treeModel;\r      }\r\r     private void describeTreeSubNodes(Vector vcNodes, DefaultTreeModel treeModel, DefaultMutableTreeNode nodeParent, String basePath, String baseNodeName) {\r               DefaultMutableTreeNode thisNode = new DefaultMutableTreeNode(baseNodeName);\r            treeModel.insertNodeInto(thisNode, nodeParent, treeModel.getChildCount(nodeParent));\r           boolean inSubNode = true;\r              String fullNodePath = basePath + baseNodeName + File.separator;\r                while(inSubNode && vcNodes.size() > 0) {\r                       String nodeName = (String)(vcNodes.elementAt(0));\r                      if(nodeName.startsWith(fullNodePath)) {\r                                nodeName = nodeName.substring(fullNodePath.length());\r                          if(nodeName.indexOf(File.separator) > -1) {\r                                    String baseNode = nodeName.substring(0, nodeName.indexOf(File.separator));\r                                     describeTreeSubNodes(vcNodes, treeModel, thisNode, fullNodePath, baseNode);\r                            }\r                              else {\r                                 treeModel.insertNodeInto(new DefaultMutableTreeNode(nodeName), thisNode, treeModel.getChildCount(thisNode));\r                                   vcNodes.removeElementAt(0);\r                            }\r                      }\r                      else {\r                         inSubNode = false;\r                     }\r              }\r      }\r\r     private Vector fetchListing() {\r                Vector vcFetch = new Vector();\r         if(rootFile.isDirectory()) {\r                   vcFetch.add(exploreFolder("", rootFile, new Vector(), 1));\r             }\r              else {\r                 String fullFile = rootFile.getAbsolutePath().trim();\r                   if(!bScreenExtensions || (bScreenExtensions && screensOkay(fullFile))) {\r                               vcFetch.add(fullFile);\r                 }\r              }\r              return describeListing(vcFetch);\r       }\r\r     private Vector trimToName(Vector fullFiles) {\r          Vector vcReturn = new Vector(fullFiles.size());\r                for(int i = 0; i < fullFiles.size(); i++) {\r                    String trimName = (String)(fullFiles.elementAt(i));\r                    if(trimName.indexOf(File.separator) > -1) {\r                            vcReturn.add(trimName.substring(trimName.lastIndexOf(File.separator) + 1, trimName.length()));\r                 }\r                      else {\r                         vcReturn.add(trimName);\r                        }\r              }\r              return vcReturn;\r       }\r\r     /* Recursively explores file folders and subfolders, adding all files which match the filtered type\r       to the returning Vector.\r     */\r    private Vector exploreFolder(String currentLocal, File folder, Vector vcWorking, int currDepth) {\r              if((maxDepth != 0) && currDepth > maxDepth) {\r                  return vcWorking;\r              }\r              String fullDescriptor = currentLocal + File.separator + folder.getName();\r              File[] contents = folder.listFiles();\r          for(int i = 0; i < contents.length; i++) {\r                     if(contents[i].isDirectory()) {\r                                vcWorking.add(exploreFolder(fullDescriptor, contents[i], new Vector(), currDepth + 1));\r                        }\r                      else {\r                         String completeName = contents[i].getAbsolutePath();\r                           if(bFileNamesOnly) { completeName = contents[i].getName(); }\r                           if(!bScreenExtensions || (bScreenExtensions && screensOkay(completeName))) {\r                                   vcWorking.add(completeName.trim());\r                            }\r                      }\r              }\r              Collections.sort(vcWorking, localComparison);\r          return vcWorking;\r      }       \r\r      /* Explores only current file folder, adding all files which match the filtered type\r      to the returning Vector.\r     */\r    private Vector exploreFolderOnly(String currentLocal, File folder, Vector vcWorking) {\r         String fullDescriptor = currentLocal + File.separator + folder.getName();\r              File[] contents = folder.listFiles();\r          for(int i = 0; i < contents.length; i++) {\r                     if(contents[i].isDirectory()) {\r                                /* ignore */\r                   }\r                      else {\r                         String completeName = contents[i].getAbsolutePath();\r                           if(bFileNamesOnly) { completeName = contents[i].getName(); }\r                           if(!bScreenExtensions || (bScreenExtensions && screensOkay(completeName))) {\r                                   vcWorking.add(completeName.trim());\r                            }\r                      }\r              }\r              Collections.sort(vcWorking, localComparison);\r          return vcWorking;\r      }       \r\r      private Vector describeListing(Vector vcTree) {\r                Collections.sort(vcTree, localComparison);\r             Vector vcDescription = new Vector();\r           for(int i = 0; i < vcTree.size(); i++) {\r                       if(vcTree.elementAt(i) instanceof Vector) {\r                            describeNode((Vector)(vcTree.elementAt(i)), vcDescription);\r                    }\r                      else {\r                         vcDescription.add(vcTree.elementAt(i));\r                        }\r              }\r              return vcDescription;\r  }\r\r     private void describeNode(Vector vcNode, Vector vcStore) {\r             for(int i = 0; i < vcNode.size(); i++) {\r                       if(vcNode.elementAt(i) instanceof Vector) {\r                            describeNode((Vector)(vcNode.elementAt(i)), vcStore);\r                  }\r                      else {\r                         vcStore.add(vcNode.elementAt(i));\r                      }\r              }\r      }\r\r     private boolean screensOkay(String filename) {\r         for(int i = 0; i < vcExtensions.size(); i++) {\r                 String extension = ((String)(vcExtensions.elementAt(i))).toLowerCase();\r                        if(filename.toLowerCase().endsWith(extension)) {\r                               return true;\r                   }\r              }\r              return false;\r  }\r\r//  Accessor Methods ------------------------------------------------------------------------>\r\r     public File    getRootFile()        { return rootFile; }\r       public Vector  getFiles()           { return vcFiles; }\r        public Vector  getExtensions()      { return vcExtensions; }\r   public int     getMaxDepth()        { return maxDepth; }\r       public boolean doScreenExtensions() { return bScreenExtensions; }\r      public boolean showFileNamesOnly()  { return bFileNamesOnly; }\r public boolean getDisplayMode()     { return bDisplayMode; }\r\r  public void setRootFile(File f)            { rootFile = f; }\r   public void setFiles(Vector vc)            { vcFiles = vc; }\r   public void setExtensions(Vector vc)       {\r           vcExtensions = vc;\r             if(vcExtensions.size() > 0) {\r                  setScreenExtensions(true);\r             }\r              else {\r                 setScreenExtensions(false);\r            }\r      }\r      public void setMaxDepth(int i)             { maxDepth = i; }\r   public void setScreenExtensions(boolean b) { bScreenExtensions = b; }\r  public void setFileNamesOnly(boolean b)    { bFileNamesOnly = b; }\r     public void setDisplayMode(boolean b)      { bDisplayMode = b; }\r\r//  Unit Test Method ------------------------------------------------------------------------>\r\r      /** Unit test method for testing the code with example settings */\r     public static void unitTest(String dir) {\r              Vector vcCommonExts = new Vector();\r            vcCommonExts.add(".java");\r             vcCommonExts.add(".class");\r            vcCommonExts.add(".txt");\r              vcCommonExts.add(".html");\r             vcCommonExts.add(".htm");\r              vcCommonExts.add(".gif");\r              vcCommonExts.add(".jpeg");\r             vcCommonExts.add(".jpg");\r              TreeSpider testSpider = new TreeSpider(dir, vcCommonExts, false, 0);\r           System.out.println("UNIT TEST SCAN");\r          Hashtable htColl = testSpider.collectListing();\r                Enumeration enumKeys = htColl.keys();\r          while(enumKeys.hasMoreElements()) {\r                    String key = (String)(enumKeys.nextElement());\r                 System.out.println(key);\r                       Vector vcValues = (Vector)(htColl.get(key));\r                   for(int i = 0; i < vcValues.size(); i++) {\r                             System.out.println("  " + vcValues.elementAt(i));\r                      }\r              }\r      }\r\r//  Main Method ----------------------------------------------------------------------------->\r\r     public static void main(String[] args) {\r               if(args.length < 1) {\r                  try {\r                          TreeSpider.unitTest((new File(".")).getCanonicalPath());\r                       }\r                      catch(java.io.IOException ioe) {\r                               System.out.println("Unable to resolve current directory. Please specify a directory explicitly.");\r                             System.exit(1);\r                        }\r              }\r              else {\r                 TreeSpider.unitTest(args[0]);\r          }\r      }\r\r//  Inner Classes --------------------------------------------------------------------------->\r\r     /* Class for sorting file listings by directory then name */\r   class FileTreeComparator implements Comparator\r {\r              private boolean isCaseSensitive;\r\r              public FileTreeComparator(boolean caseCheck) {\r                 isCaseSensitive = caseCheck;\r           }\r\r             public FileTreeComparator() {\r                  isCaseSensitive = true;\r                }\r\r             public int compare(Object objA, Object objB) {\r                 if(objA instanceof Vector) {\r                           if(objB instanceof Vector) {\r                                   if(((Vector)(objA)).size() < 1)\r                                        {\r                                              return -1;\r                                     }\r                                      else if(((Vector)(objB)).size() < 1)\r                                   {\r                                              return 1;\r                                      }\r                                      else\r                                   {\r                                              return compare(((Vector)(objA)).elementAt(0), ((Vector)(objB)).elementAt(0));\r                                  }\r                              }\r                              else {\r                                 return 1;\r                              }\r                      }\r                      else if(objB instanceof Vector) {\r                              return -1;\r                     }\r                      else {\r                         String strA = (String)objA;\r                            String strB = (String)objB;\r                            return (isCaseSensitive ? strA.compareTo(strB) : strA.compareToIgnoreCase(strB));\r                      }\r              }\r      }\r\r}
\ No newline at end of file
diff --git a/ekit/ekit.css b/ekit/ekit.css
new file mode 100644 (file)
index 0000000..09d796c
--- /dev/null
@@ -0,0 +1,6 @@
+h1 { color : #8f8f2f; font-family : monospaced; }\r
+.highlight { background-color: #ffffaa; color: #000000; }\r
+.notice { color : #1f8f1f; }\r
+.invert { background-color: #000000; color: #ffffff; }\r
+.warning { color: #cc5555; }\r
+\r
\ No newline at end of file