From b41551c9e2757b3b9d9501853a838177614123b0 Mon Sep 17 00:00:00 2001 From: Skylar Date: Thu, 14 May 2015 00:42:19 -0600 Subject: [PATCH] Codebase Sync --- build.xml | 146 +- nbproject/build-impl.xml | 2877 ++++++++--------- nbproject/genfiles.properties | 16 +- nbproject/project.properties | 256 +- nbproject/project.xml | 33 +- src/net/apocalypselabs/symat/Debug.java | 146 +- src/net/apocalypselabs/symat/Functions.java | 2594 +++++++-------- src/net/apocalypselabs/symat/Main.java | 2297 ++++++------- .../apocalypselabs/symat/SplashScreen.java | 558 ++-- src/net/apocalypselabs/symat/functions.js | 62 +- src/net/apocalypselabs/symat/pretty.css | 50 +- 11 files changed, 4506 insertions(+), 4529 deletions(-) diff --git a/build.xml b/build.xml index 44ed88f..cc8db15 100644 --- a/build.xml +++ b/build.xml @@ -1,73 +1,73 @@ - - - - - - - - - - - Builds, tests, and runs the project SyMAT. - - - + + + + + + + + + + + Builds, tests, and runs the project SyMAT. + + + diff --git a/nbproject/build-impl.xml b/nbproject/build-impl.xml index b0e40ae..302d494 100644 --- a/nbproject/build-impl.xml +++ b/nbproject/build-impl.xml @@ -1,1456 +1,1421 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Must set platform.home - Must set platform.bootcp - Must set platform.java - Must set platform.javac - - The J2SE Platform is not correctly set up. - Your active platform is: ${platform.active}, but the corresponding property "platforms.${platform.active}.home" is not found in the project's properties files. - Either open the project in the IDE and setup the Platform with the same name or add it manually. - For example like this: - ant -Duser.properties.file=<path_to_property_file> jar (where you put the property "platforms.${platform.active}.home" in a .properties file) - or ant -Dplatforms.${platform.active}.home=<path_to_JDK_home> jar (where no properties file is used) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Must set src.dir - Must set build.dir - Must set dist.dir - Must set build.classes.dir - Must set dist.javadoc.dir - Must set build.test.classes.dir - Must set build.test.results.dir - Must set build.classes.excludes - Must set dist.jar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Must set javac.includes - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - No tests executed. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Must set JVM to use for profiling in profiler.info.jvm - Must set profiler agent JVM arguments in profiler.info.jvmargs.agent - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Must select some files in the IDE or set javac.includes - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - To run this application from the command line without Ant, try: - - ${platform.java} -jar "${dist.jar.resolved}" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Must select one file in the IDE or set run.class - - - - Must select one file in the IDE or set run.class - - - - - - - - - - - - - - - - - - - - - - - Must select one file in the IDE or set debug.class - - - - - Must select one file in the IDE or set debug.class - - - - - Must set fix.includes - - - - - - - - - - This target only works when run from inside the NetBeans IDE. - - - - - - - - - Must select one file in the IDE or set profile.class - This target only works when run from inside the NetBeans IDE. - - - - - - - - - This target only works when run from inside the NetBeans IDE. - - - - - - - - - - - - - This target only works when run from inside the NetBeans IDE. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Must select one file in the IDE or set run.class - - - - - - Must select some files in the IDE or set test.includes - - - - - Must select one file in the IDE or set run.class - - - - - Must select one file in the IDE or set applet.url - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Must select some files in the IDE or set javac.includes - - - - - - - - - - - - - - - - - - Some tests failed; see details above. - - - - - - - - - Must select some files in the IDE or set test.includes - - - - Some tests failed; see details above. - - - - Must select some files in the IDE or set test.class - Must select some method in the IDE or set test.method - - - - Some tests failed; see details above. - - - - - Must select one file in the IDE or set test.class - - - - Must select one file in the IDE or set test.class - Must select some method in the IDE or set test.method - - - - - - - - - - - - - - Must select one file in the IDE or set applet.url - - - - - - - - - Must select one file in the IDE or set applet.url - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set src.dir + Must set build.dir + Must set dist.dir + Must set build.classes.dir + Must set dist.javadoc.dir + Must set build.test.classes.dir + Must set build.test.results.dir + Must set build.classes.excludes + Must set dist.jar + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + No tests executed. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set JVM to use for profiling in profiler.info.jvm + Must set profiler agent JVM arguments in profiler.info.jvmargs.agent + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + To run this application from the command line without Ant, try: + + java -jar "${dist.jar.resolved}" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set run.class + + + + Must select one file in the IDE or set run.class + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set debug.class + + + + + Must select one file in the IDE or set debug.class + + + + + Must set fix.includes + + + + + + + + + + This target only works when run from inside the NetBeans IDE. + + + + + + + + + Must select one file in the IDE or set profile.class + This target only works when run from inside the NetBeans IDE. + + + + + + + + + This target only works when run from inside the NetBeans IDE. + + + + + + + + + + + + + This target only works when run from inside the NetBeans IDE. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set run.class + + + + + + Must select some files in the IDE or set test.includes + + + + + Must select one file in the IDE or set run.class + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + Some tests failed; see details above. + + + + + + + + + Must select some files in the IDE or set test.includes + + + + Some tests failed; see details above. + + + + Must select some files in the IDE or set test.class + Must select some method in the IDE or set test.method + + + + Some tests failed; see details above. + + + + + Must select one file in the IDE or set test.class + + + + Must select one file in the IDE or set test.class + Must select some method in the IDE or set test.method + + + + + + + + + + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/nbproject/genfiles.properties b/nbproject/genfiles.properties index d4c64e8..dbf3943 100644 --- a/nbproject/genfiles.properties +++ b/nbproject/genfiles.properties @@ -1,8 +1,8 @@ -build.xml.data.CRC32=0dfe898c -build.xml.script.CRC32=cfce77fe -build.xml.stylesheet.CRC32=8064a381@1.75.2.48 -# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. -# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. -nbproject/build-impl.xml.data.CRC32=0dfe898c -nbproject/build-impl.xml.script.CRC32=eaffabc7 -nbproject/build-impl.xml.stylesheet.CRC32=876e7a8f@1.75.2.48 +build.xml.data.CRC32=70b2413f +build.xml.script.CRC32=cfce77fe +build.xml.stylesheet.CRC32=8064a381@1.75.2.48 +# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. +# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. +nbproject/build-impl.xml.data.CRC32=70b2413f +nbproject/build-impl.xml.script.CRC32=e6773cad +nbproject/build-impl.xml.stylesheet.CRC32=876e7a8f@1.75.2.48 diff --git a/nbproject/project.properties b/nbproject/project.properties index 0a320f8..8c18150 100644 --- a/nbproject/project.properties +++ b/nbproject/project.properties @@ -1,128 +1,128 @@ -annotation.processing.enabled=true -annotation.processing.enabled.in.editor=false -annotation.processing.processors.list= -annotation.processing.run.all.processors=true -annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output -application.desc=Teach, learn, and use math and programming skills with SyMAT. -application.homepage=https://symatapp.com/ -application.splash=C:\\Users\\Skylar\\Documents\\Apocalypse Labs\\appmedia\\SyMAT\\splashscreen.png -application.title=SyMAT -application.vendor=Apocalypse Laboratories -auxiliary.org-netbeans-spi-editor-hints-projects.perProjectHintSettingsFile=nbproject/cfg_hints.xml -build.classes.dir=${build.dir}/classes -build.classes.excludes=**/*.java,**/*.form -# This directory is removed when the project is cleaned: -build.dir=build -build.generated.dir=${build.dir}/generated -build.generated.sources.dir=${build.dir}/generated-sources -# Only compile against the classpath explicitly listed here: -build.sysclasspath=ignore -build.test.classes.dir=${build.dir}/test/classes -build.test.results.dir=${build.dir}/test/results -# Uncomment to specify the preferred debugger connection transport: -#debug.transport=dt_socket -debug.classpath=\ - ${run.classpath} -debug.test.classpath=\ - ${run.test.classpath} -# Files in build.classes.dir which should be excluded from distribution jar -dist.archive.excludes= -# This directory is removed when the project is cleaned: -dist.dir=dist -dist.jar=${dist.dir}/SyMAT.jar -dist.javadoc.dir=${dist.dir}/javadoc -endorsed.classpath= -excludes= -file.reference.autocomplete-2.5.4.jar=lib/autocomplete-2.5.4.jar -file.reference.beautyeye_lnf.jar=lib/beautyeye_lnf.jar -file.reference.flamingo-6.3.jar=lib/flamingo-6.3.jar -file.reference.htmlcleaner-2.10.jar=lib/htmlcleaner-2.10.jar -file.reference.iText-4.2.0-com.itextpdf.jar=lib/iText-4.2.0-com.itextpdf.jar -file.reference.JavaPrettify-1.2.1.jar=lib\\JavaPrettify-1.2.1.jar -file.reference.jmathplot.jar=lib/jmathplot.jar -file.reference.js-engine.jar=lib/js-engine.jar -file.reference.js.jar=lib/js.jar -file.reference.json-simple-1.1.1.jar=lib/json-simple-1.1.1.jar -file.reference.jython-standalone-2.7-b3.jar=lib/jython-standalone-2.7-b3.jar -file.reference.log4j-1.2.11.jar=lib/log4j-1.2.11.jar -file.reference.rsyntaxtextarea-2.5.6.jar=lib/rsyntaxtextarea-2.5.6.jar -file.reference.seaglasslookandfeel-0.2.jar=lib/seaglasslookandfeel-0.2.jar -file.reference.SyMAT-src=src -file.reference.symja-2014-11-01.jar=lib/symja-2014-11-01.jar -file.reference.trident-6.3.jar=lib/trident-6.3.jar -includes=** -jar.archive.disabled=${jnlp.enabled} -jar.compress=false -jar.index=${jnlp.enabled} -javac.classpath=\ - ${file.reference.autocomplete-2.5.4.jar}:\ - ${file.reference.beautyeye_lnf.jar}:\ - ${file.reference.flamingo-6.3.jar}:\ - ${file.reference.htmlcleaner-2.10.jar}:\ - ${file.reference.iText-4.2.0-com.itextpdf.jar}:\ - ${file.reference.jmathplot.jar}:\ - ${file.reference.js-engine.jar}:\ - ${file.reference.js.jar}:\ - ${file.reference.json-simple-1.1.1.jar}:\ - ${file.reference.jython-standalone-2.7-b3.jar}:\ - ${file.reference.log4j-1.2.11.jar}:\ - ${file.reference.rsyntaxtextarea-2.5.6.jar}:\ - ${file.reference.seaglasslookandfeel-0.2.jar}:\ - ${file.reference.symja-2014-11-01.jar}:\ - ${file.reference.trident-6.3.jar}:\ - ${file.reference.JavaPrettify-1.2.1.jar} -# Space-separated list of extra javac options -javac.compilerargs= -javac.deprecation=false -javac.processorpath=\ - ${javac.classpath} -javac.source=1.8 -javac.target=1.8 -javac.test.classpath=\ - ${javac.classpath}:\ - ${build.classes.dir} -javac.test.processorpath=\ - ${javac.test.classpath} -javadoc.additionalparam= -javadoc.author=false -javadoc.encoding=${source.encoding} -javadoc.noindex=false -javadoc.nonavbar=false -javadoc.notree=false -javadoc.private=false -javadoc.reference.flamingo-6.3.jar=lib/flamingo-6.3-javadoc.jar -javadoc.splitindex=true -javadoc.use=true -javadoc.version=false -javadoc.windowtitle= -jnlp.codebase.type=no.codebase -jnlp.descriptor=application -jnlp.enabled=false -jnlp.mixed.code=default -jnlp.offline-allowed=false -jnlp.signed=false -jnlp.signing= -jnlp.signing.alias= -jnlp.signing.keystore= -main.class=net.apocalypselabs.symat.Main -# Optional override of default Codebase manifest attribute, use to prevent RIAs from being repurposed -manifest.custom.codebase= -# Optional override of default Permissions manifest attribute (supported values: sandbox, all-permissions) -manifest.custom.permissions= -manifest.file=manifest.mf -meta.inf.dir=${src.dir}/META-INF -mkdist.disabled=false -platform.active=JDK_1.8 -project.license=aplabs-oss_1 -run.classpath=\ - ${javac.classpath}:\ - ${build.classes.dir} -# Space-separated list of JVM arguments used when running the project. -# You may also define separate properties like run-sys-prop.name=value instead of -Dname=value. -# To set system properties for unit tests define test-sys-prop.name=value: -run.jvmargs= -run.test.classpath=\ - ${javac.test.classpath}:\ - ${build.test.classes.dir} -source.encoding=UTF-8 -src.dir=${file.reference.SyMAT-src} +annotation.processing.enabled=true +annotation.processing.enabled.in.editor=false +annotation.processing.processors.list= +annotation.processing.run.all.processors=true +annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output +application.desc=Math and Programming for People +application.homepage=https://symatapp.com/ +application.splash=C:\\Users\\Skylar\\Documents\\Apocalypse Labs\\appmedia\\SyMAT\\splashscreen.png +application.title=SyMAT +application.vendor=Apocalypse Laboratories +auxiliary.org-netbeans-spi-editor-hints-projects.perProjectHintSettingsFile=nbproject/cfg_hints.xml +build.classes.dir=${build.dir}/classes +build.classes.excludes=**/*.java,**/*.form +# This directory is removed when the project is cleaned: +build.dir=build +build.generated.dir=${build.dir}/generated +build.generated.sources.dir=${build.dir}/generated-sources +# Only compile against the classpath explicitly listed here: +build.sysclasspath=ignore +build.test.classes.dir=${build.dir}/test/classes +build.test.results.dir=${build.dir}/test/results +# Uncomment to specify the preferred debugger connection transport: +#debug.transport=dt_socket +debug.classpath=\ + ${run.classpath} +debug.test.classpath=\ + ${run.test.classpath} +# Files in build.classes.dir which should be excluded from distribution jar +dist.archive.excludes= +# This directory is removed when the project is cleaned: +dist.dir=dist +dist.jar=${dist.dir}/SyMAT.jar +dist.javadoc.dir=${dist.dir}/javadoc +endorsed.classpath= +excludes= +file.reference.autocomplete-2.5.4.jar=lib/autocomplete-2.5.4.jar +file.reference.beautyeye_lnf.jar=lib/beautyeye_lnf.jar +file.reference.flamingo-6.3.jar=lib/flamingo-6.3.jar +file.reference.htmlcleaner-2.10.jar=lib/htmlcleaner-2.10.jar +file.reference.iText-4.2.0-com.itextpdf.jar=lib/iText-4.2.0-com.itextpdf.jar +file.reference.JavaPrettify-1.2.1.jar=lib\\JavaPrettify-1.2.1.jar +file.reference.jmathplot.jar=lib/jmathplot.jar +file.reference.js-engine.jar=lib/js-engine.jar +file.reference.js.jar=lib/js.jar +file.reference.json-simple-1.1.1.jar=lib/json-simple-1.1.1.jar +file.reference.jython-standalone-2.7-b3.jar=lib/jython-standalone-2.7-b3.jar +file.reference.log4j-1.2.11.jar=lib/log4j-1.2.11.jar +file.reference.rsyntaxtextarea-2.5.6.jar=lib/rsyntaxtextarea-2.5.6.jar +file.reference.seaglasslookandfeel-0.2.jar=lib/seaglasslookandfeel-0.2.jar +file.reference.SyMAT-src=src +file.reference.symja-2014-11-01.jar=lib/symja-2014-11-01.jar +file.reference.trident-6.3.jar=lib/trident-6.3.jar +includes=** +jar.archive.disabled=${jnlp.enabled} +jar.compress=false +jar.index=${jnlp.enabled} +javac.classpath=\ + ${file.reference.autocomplete-2.5.4.jar}:\ + ${file.reference.beautyeye_lnf.jar}:\ + ${file.reference.flamingo-6.3.jar}:\ + ${file.reference.htmlcleaner-2.10.jar}:\ + ${file.reference.iText-4.2.0-com.itextpdf.jar}:\ + ${file.reference.jmathplot.jar}:\ + ${file.reference.js-engine.jar}:\ + ${file.reference.js.jar}:\ + ${file.reference.json-simple-1.1.1.jar}:\ + ${file.reference.jython-standalone-2.7-b3.jar}:\ + ${file.reference.log4j-1.2.11.jar}:\ + ${file.reference.rsyntaxtextarea-2.5.6.jar}:\ + ${file.reference.seaglasslookandfeel-0.2.jar}:\ + ${file.reference.symja-2014-11-01.jar}:\ + ${file.reference.trident-6.3.jar}:\ + ${file.reference.JavaPrettify-1.2.1.jar} +# Space-separated list of extra javac options +javac.compilerargs= +javac.deprecation=false +javac.processorpath=\ + ${javac.classpath} +javac.source=1.8 +javac.target=1.8 +javac.test.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir} +javac.test.processorpath=\ + ${javac.test.classpath} +javadoc.additionalparam= +javadoc.author=false +javadoc.encoding=${source.encoding} +javadoc.noindex=false +javadoc.nonavbar=false +javadoc.notree=false +javadoc.private=false +javadoc.reference.flamingo-6.3.jar=lib/flamingo-6.3-javadoc.jar +javadoc.splitindex=true +javadoc.use=true +javadoc.version=false +javadoc.windowtitle= +jnlp.codebase.type=no.codebase +jnlp.descriptor=application +jnlp.enabled=false +jnlp.mixed.code=default +jnlp.offline-allowed=false +jnlp.signed=false +jnlp.signing= +jnlp.signing.alias= +jnlp.signing.keystore= +main.class=net.apocalypselabs.symat.Main +# Optional override of default Codebase manifest attribute, use to prevent RIAs from being repurposed +manifest.custom.codebase= +# Optional override of default Permissions manifest attribute (supported values: sandbox, all-permissions) +manifest.custom.permissions= +manifest.file=manifest.mf +meta.inf.dir=${src.dir}/META-INF +mkdist.disabled=false +platform.active=default_platform +project.license=aplabs-oss_1 +run.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir} +# Space-separated list of JVM arguments used when running the project. +# You may also define separate properties like run-sys-prop.name=value instead of -Dname=value. +# To set system properties for unit tests define test-sys-prop.name=value: +run.jvmargs= +run.test.classpath=\ + ${javac.test.classpath}:\ + ${build.test.classes.dir} +source.encoding=UTF-8 +src.dir=${file.reference.SyMAT-src} diff --git a/nbproject/project.xml b/nbproject/project.xml index 03d903d..66bf976 100644 --- a/nbproject/project.xml +++ b/nbproject/project.xml @@ -1,17 +1,16 @@ - - - org.netbeans.modules.java.j2seproject - - - SyMAT - - - - - - - - .\lib\nblibraries.properties - - - + + + org.netbeans.modules.java.j2seproject + + + SyMAT + + + + + + + .\lib\nblibraries.properties + + + diff --git a/src/net/apocalypselabs/symat/Debug.java b/src/net/apocalypselabs/symat/Debug.java index 1b8bfd2..b71ed07 100644 --- a/src/net/apocalypselabs/symat/Debug.java +++ b/src/net/apocalypselabs/symat/Debug.java @@ -1,73 +1,73 @@ -/* - * This class is public domain because it is standalone and - * is potentially useful to other projects. - * - * If this cannot be placed in the public domain, it is licensed under - * the Creative Commons Zero license. - * - * Feel free to use it however you wish! - */ -package net.apocalypselabs.symat; - -/** - * This class handles debug logging, so it's easy to disable. - * - * @author Skylar - */ -public class Debug { - - // If output should be on or off - public static boolean debug = true; - - /** - * Turn debug output on and off. - * - * @param b - */ - public static void setDebug(boolean b) { - debug = b; - } - - /** - * Check if debug output is enabled. - * - * @return true if it is. - */ - public static boolean getDebug() { - return debug; - } - - /** - * Call System.out.println(data) if debug output enabled. - * - * @param data Data to print. - */ - public static void println(Object data) { - if (debug) { - System.out.println(data); - } - } - - /** - * Call System.err.println(data) if debug output enabled. - * - * @param data Data to print. - */ - public static void printerr(Object data) { - if (debug) { - System.err.println(data); - } - } - - /** - * Call e.printStackTrace() if debug output enabled. - * - * @param e an Exception. - */ - @SuppressWarnings(value = {"CallToPrintStackTrace"}) - public static void stacktrace(Exception e) { - if (debug) { - e.printStackTrace(); - } - } -} +/* + * This class is public domain because it is standalone and + * is potentially useful to other projects. + * + * If this cannot be placed in the public domain, it is licensed under + * the Creative Commons Zero license. + * + * Feel free to use it however you wish! + */ +package net.apocalypselabs.symat; + +/** + * This class handles debug logging, so it's easy to disable. + * + * @author Skylar + */ +public class Debug { + + // If output should be on or off + public static boolean debug = true; + + /** + * Turn debug output on and off. + * + * @param b + */ + public static void setDebug(boolean b) { + debug = b; + } + + /** + * Check if debug output is enabled. + * + * @return true if it is. + */ + public static boolean getDebug() { + return debug; + } + + /** + * Call System.out.println(data) if debug output enabled. + * + * @param data Data to print. + */ + public static void println(Object data) { + if (debug) { + System.out.println(data); + } + } + + /** + * Call System.err.println(data) if debug output enabled. + * + * @param data Data to print. + */ + public static void printerr(Object data) { + if (debug) { + System.err.println(data); + } + } + + /** + * Call e.printStackTrace() if debug output enabled. + * + * @param e an Exception. + */ + @SuppressWarnings(value = {"CallToPrintStackTrace"}) + public static void stacktrace(Exception e) { + if (debug) { + e.printStackTrace(); + } + } +} diff --git a/src/net/apocalypselabs/symat/Functions.java b/src/net/apocalypselabs/symat/Functions.java index ce86084..d5e9c55 100644 --- a/src/net/apocalypselabs/symat/Functions.java +++ b/src/net/apocalypselabs/symat/Functions.java @@ -1,1297 +1,1297 @@ -/* - * CODE LICENSE ===================== - * Copyright (c) 2015, Apocalypse Laboratories - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors - * may be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * 4. You adhere to the Media License detailed below. If you do not, this license - * is automatically revoked and you must purge all copies of the software you - * possess, in source or binary form. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * MEDIA LICENSE ==================== - * All images and other graphical files (the "graphics") included with this - * software are copyright (c) 2015 Apocalypse Laboratories. You may not distribute - * the graphics or any program, source code repository, or other digital storage - * media containing them without written permission from Apocalypse Laboratories. - * This ban on distribution only applies to publicly available systems. - * A password-protected network file share, USB drive, or other storage scheme that - * cannot be easily accessed by the public is generally allowed. If in doubt, - * contact Apocalypse Laboratories. If Apocalypse Laboratories allows or denies - * you permission, that decision is considered final and binding. - */ -package net.apocalypselabs.symat; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import static java.lang.Math.*; -import java.lang.reflect.Array; -import java.math.BigInteger; -import java.net.URL; -import java.security.SecureRandom; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Calendar; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.NoSuchElementException; -import java.util.Set; -import java.util.prefs.Preferences; -import javax.swing.JFileChooser; -import javax.swing.JOptionPane; -import static net.apocalypselabs.symat.Main.API_URL; -import net.apocalypselabs.symat.components.TextBox; -import org.matheclipse.core.eval.EvalUtilities; -import org.matheclipse.core.interfaces.IExpr; -import org.matheclipse.parser.client.math.MathException; -import org.mozilla.javascript.NativeArray; -import org.python.core.PyList; - -/** - * These functions are accessible from JavaScript. - * - * There are a lot of aliases in here too. - * - * @author Skylar - */ -public class Functions { - - public static final HashMap GLOBALS = new HashMap<>(); - - private final EvalUtilities util = new EvalUtilities(true, true); - Graph graphwin = new Graph(true); - - private String lang = "py"; - - private final SecureRandom rng = new SecureRandom(); - - /* - Useful interactions - */ - /** - * Display a message dialog box. - * - * @param message The message to give. - */ - public void notify(Object message) { - JOptionPane.showInternalMessageDialog(Main.mainPane, message.toString()); - } - - /** - * Display message dialog. - * - * This is an alias to help JavaScript programmers. - * - * @param message The message - */ - public void alert(Object message) { - notify(message); - } - - /** - * Display an input dialog box with a text field. - * - * @param question Text to label dialog - * @return The inputted text - */ - public String ask(String question) { - return JOptionPane.showInternalInputDialog(Main.mainPane, question); - } - - /** - * Pause execution for the specified number of milliseconds. - * - * @param millis - */ - public void pause(long millis) { - try { - Thread.sleep(millis); - } catch (InterruptedException e) { - // Nothing to do. - } - } - - /** - * @see pause() - * @param millis - */ - public void sleep(long millis) { - pause(millis); - } - - /** - * Quit SyMAT. - */ - public void quitApplication() { - System.exit(0); - } - - /* - Math commands - */ - /** - * Find the factorial (n!) of a number. - * - * @param n positive integer - * @return n! as String - * @throws net.apocalypselabs.symat.BadInputException - */ - public String factorial(long n) throws BadInputException { - if (n <= 0) { - throw new BadInputException("Input must be greater than zero!"); - } - - BigInteger inc = new BigInteger("1"); - BigInteger fact = new BigInteger("1"); - - for (long c = 1; c <= n; c++) { - fact = fact.multiply(inc); - inc = inc.add(BigInteger.ONE); - } - return fact.toString(); - } - - /** - * Take (a^b) mod m. If b is -1, finds the modular inverse of a mod m. - * - * @param a Number - * @param b Exponent - * @param m Modulus - * @return pow(a,b)%m. - */ - public double powermod(double a, double b, double m) { - if (b == -1) { - BigInteger in = new BigInteger(String.valueOf((int) a)); - return in.modInverse(new BigInteger(String.valueOf((int) m))).doubleValue(); - } - return (pow(a, b) % m + m) % m; - } - - /** - * Take (a^b) mod m. If b is -1, finds the modular inverse of a mod m. - * - * @param a Number - * @param b Exponent - * @param m Modulus - * @return pow(a,b)%m. - */ - public String powermod(String a, String b, String m) { - BigInteger in = new BigInteger(a); - if (b.equals("-1")) { - return in.modInverse(new BigInteger(m)).toString(); - } - return in.modPow(new BigInteger(b), new BigInteger(m)).toString(); - } - - public long gcd(long a, long b) { - if (b == 0) { - return a; - } - return gcd(b, a % b); - } - - public String gcd(String a, String b) { - return (new BigInteger(a).gcd(new BigInteger(b)).toString()); - } - - /** - * Differentiate the function with respect to idv. - * - * @param function Function - * @param idv independent variable - * @return Differentiated function - */ - public String diff(String function, String idv) { - return util.evaluate("diff(" + function + "," + idv + ")").toString(); - } - - /** - * Differentiate the function with respect to x. - * - * @param function Function - * @return Differentiated function - */ - public String diff(String function) { - // Assume "x" as var - return diff(function, "x"); - } - - @Deprecated - public String D(String function, String idv) { - return diff(function, idv); - } - - public double[] solve(String function, String idv, int eq) { - String res = $("Solve[" + function + "==" + eq + ", " + idv + "]"); - res = res.substring(1, res.length() - 1); - String[] cmp = res.split(","); - for (int i = 0; i < cmp.length; i++) { - cmp[i] = cmp[i].replace("{" + idv + "->", ""); - cmp[i] = cmp[i].replace("}", ""); - } - double[] out = new double[cmp.length]; - for (int i = 0; i < cmp.length; i++) { - try { - if (cmp[i].contains("I")) { - if (cmp[i].contains("-I")) { - out[i] = Double.NEGATIVE_INFINITY; - } else { - out[i] = Double.POSITIVE_INFINITY; - } - } else { - out[i] = Double.parseDouble(cmp[i]); - } - } catch (Exception ex) { - return new double[]{Double.NaN}; - } - } - return out; - } - - public double[] solve(String function, String idv) { - return solve(function, idv, 0); - } - - public double[] solve(String function) { - return solve(function, "x"); - } - - private String printa(double[] o) { - String out = "["; - for (int i = 0; i < o.length; i++) { - out += o[i] + (i == o.length - 1 ? "" : ", "); - } - out += "]"; - return out; - } - - private String printa(int[] o) { - String out = "["; - for (int i = 0; i < o.length; i++) { - out += o[i] + (i == o.length - 1 ? "" : ", "); - } - out += "]"; - return out; - } - - private String printa(boolean[] o) { - String out = "["; - for (int i = 0; i < o.length; i++) { - out += (o[i] ? "true" : "false") + (i == o.length - 1 ? "" : ", "); - } - out += "]"; - return out; - } - - public String printa(Object o) { - String out = "["; - if (o instanceof int[]) { - int[] arr = (int[]) o; - for (int i = 0; i < arr.length; i++) { - out += arr[i] + (i == arr.length - 1 ? "" : ", "); - } - } else if (o instanceof double[]) { - double[] arr = (double[]) o; - for (int i = 0; i < arr.length; i++) { - out += arr[i] + (i == arr.length - 1 ? "" : ", "); - } - } else if (o instanceof boolean[]) { - double[] arr = (double[]) o; - for (int i = 0; i < arr.length; i++) { - out += arr[i] + (i == arr.length - 1 ? "" : ", "); - } - } else if (o instanceof int[][]) { - int[][] arr = (int[][]) o; - for (int i = 0; i < arr.length; i++) { - out += printa(arr[i]) + (i == arr.length - 1 ? "" : ", "); - } - } else if (o instanceof double[][]) { - double[][] arr = (double[][]) o; - for (int i = 0; i < arr.length; i++) { - out += printa(arr[i]) + (i == arr.length - 1 ? "" : ", "); - } - } else if (o instanceof boolean[][]) { - boolean[][] arr = (boolean[][]) o; - for (int i = 0; i < arr.length; i++) { - out += printa(arr[i]) + (i == arr.length - 1 ? "" : ", "); - } - } else if (o instanceof NativeArray) { - NativeArray arr = (NativeArray) o; - for (long i = 0; i < arr.getLength(); i++) { - - out += (arr.get(i) instanceof NativeArray ? printa(arr.get(i)) - : arr.get(i).toString()) - + (i == arr.getLength() - 1 ? "" : ", "); - } - } else if (o instanceof PyList) { - PyList arr = (PyList) o; - Object[] oo = arr.toArray(); - for (int i = 0; i < oo.length; i++) { - out += (oo[i] instanceof Object[] ? printa(oo[i]) : oo[i].toString()) - + (i == oo.length - 1 ? "" : ", "); - } - } else { - Object[] arr = (Object[]) o; - for (int i = 0; i < arr.length; i++) { - out += (arr[i] instanceof Object[] ? printa(arr[i]) : arr[i].toString()) - + (i == arr.length - 1 ? "" : ", "); - } - } - out += "]"; - return out; - } - - /** - * Integrate the function with respect to idv. - * - * @param function Function - * @param idv independent variable - * @return Integrated function - */ - public String integrate(String function, String idv) { - return util.evaluate("integrate(" + function + "," + idv + ")").toString(); - } - - /** - * Integrate the function with respect to x. - * - * @param function Function - * @return Integrated function - */ - public String integrate(String function) { - return integrate(function, "x"); - } - - public String factor(String function) { - return sym("Factor(" + function + ")"); - } - - /** - * Simplify the given expression. - * - * @param expr expression - * @return simplified expression - */ - public String simplify(String expr) { - return sym("Simplify(" + expr + ")"); - } - - public Object vpa(String expr) { - IExpr ans = util.evaluate("N(" + expr + ")"); - if (ans.isNumber()) { - return Double.parseDouble(ans.toString()); - } - return ans.toString(); - } - - public int[] primes(int in) { - boolean[] prime = new boolean[in]; - for (int i = 0; i < prime.length; i++) { - prime[i] = true; - } - for (int i = 2; i < sqrt(in); i++) { - if (prime[i]) { - int x = 0; - for (int j = i * i; j < in; j = i * i + x * i) { - prime[j] = false; - x++; - } - } - } - List arr = new ArrayList<>(); - for (int i = 2; i < prime.length; i++) { - if (prime[i]) { - arr.add(i); - } - } - int[] out = new int[arr.size()]; - for (int i = 0; i < arr.size(); i++) { - out[i] = arr.get(i); - } - return out; - } - - public double sec(double d) { - return 1.0 / Math.cos(d); - } - - public double csc(double d) { - return 1.0 / Math.sin(d); - } - - public double cot(double d) { - return 1.0 / Math.tan(d); - } - - public double asec(double d) { - return Math.acos(1.0 / d); - } - - public double acsc(double d) { - return Math.asin(1.0 / d); - } - - public double acot(double d) { - return Math.atan(1.0 / d); - } - - public double sinh(double d) { - return Math.sinh(d); - } - - public double cosh(double d) { - return Math.cosh(d); - } - - public double tanh(double d) { - return Math.tanh(d); - } - - public double sech(double d) { - return pow(Math.cosh(d), -1); - } - - public double csch(double d) { - return pow(Math.sinh(d), -1); - } - - public double coth(double d) { - return Math.cosh(d) / Math.sinh(d); - } - - /** - * Multiplies the given numbers together. - * - * @param a numbers. Calculates first * second * third, etc. - * @return The product of the numbers or the value of input if there is only - * one input. - */ - public double times(double... a) { - double ans = 0; - for (int i = 0; i < a.length; i++) { - if (i == 0) { - ans = a[i]; - } else { - ans *= a[i]; - } - } - return ans; - } - - /** - * Multiplies the given numbers together. - * - * @param a - * @param b - * @return The product of the numbers or the value of input if there is only - * one input. - */ - public String times(String a, String b) { - return (new BigInteger(a).multiply(new BigInteger(b))).toString(); - } - - /** - * Divide the given numbers. - * - * @param a numbers. Calculates (first / second) / third, etc. - * @return The quotient of the numbers or the value of input if there is - * only one input. - */ - public double divide(double... a) { - double ans = 0; - for (int i = 0; i < a.length; i++) { - if (i == 0) { - ans = a[i]; - } else { - ans /= a[i]; - } - } - return ans; - } - - /** - * Divide the given numbers. - * - * @param a - * @param b - * @return The quotient of the numbers or the value of input if there is - * only one input. - */ - public String divide(String a, String b) { - return (new BigInteger(a).divide(new BigInteger(b))).toString(); - } - - /** - * Divide the first number by the second and return the remainder. - * - * @param a numbers. Calculates (first mod second) mod third, etc. - * @return The modulus of the numbers or the value of input if there is only - * one input. - */ - public double mod(double... a) { - double ans = 0; - for (int i = 0; i < a.length; i++) { - if (i == 0) { - ans = a[i]; - } else { - ans %= a[i]; - } - } - return ans; - } - - /** - * Divide the first number by the second and return the remainder. - * - * @param a - * @param b - * @return The modulus of the numbers or the value of input if there is only - * one input. - */ - public String mod(String a, String b) { - return (new BigInteger(a).mod(new BigInteger(b))).toString(); - } - - /** - * Add the given numbers together. - * - * @param a numbers. Calculates first + second + third, etc. - * @return The sum of the numbers or the value of input if there is only one - * input. - */ - public double add(double... a) { - double ans = 0; - for (double d : a) { - ans += d; - } - return ans; - } - - /** - * Add the given numbers together. - * - * @param a numbers. Calculates first + second + third, etc. - * @return The sum of the numbers or the value of input if there is only one - * input. - */ - public String add(String a, String b) { - return (new BigInteger(a).subtract(new BigInteger(b))).toString(); - } - - /** - * Subtract the given numbers. - * - * @param a numbers. Calculates (first - second) - third, etc. - * @return The difference of the numbers or the value of input if there is - * only one input. - */ - public double subtract(double... a) { - double ans = 0; - for (int i = 0; i < a.length; i++) { - if (i == 0) { - ans = a[i]; - } else { - ans -= a[i]; - } - } - return ans; - } - - /** - * Subtract the given numbers. - * - * @param a numbers. Calculates (first - second) - third, etc. - * @return The difference of the numbers or the value of input if there is - * only one input. - */ - public String subtract(String a, String b) { - BigInteger ans = new BigInteger(a); - ans = ans.subtract(new BigInteger(b)); - return ans.toString(); - } - - public double[][] minvert(double a[][]) { - int n = a.length; - double x[][] = new double[n][n]; - double b[][] = new double[n][n]; - int index[] = new int[n]; - for (int i = 0; i < n; ++i) { - b[i][i] = 1; - } - // Transform the matrix into an upper triangle - gaussian(a, index); - // Update the matrix b[i][j] with the ratios stored - for (int i = 0; i < n - 1; ++i) { - for (int j = i + 1; j < n; ++j) { - for (int k = 0; k < n; ++k) { - b[index[j]][k] - -= a[index[j]][i] * b[index[i]][k]; - } - } - } - // Perform backward substitutions - for (int i = 0; i < n; ++i) { - x[n - 1][i] = b[index[n - 1]][i] / a[index[n - 1]][n - 1]; - for (int j = n - 2; j >= 0; --j) { - x[j][i] = b[index[j]][i]; - for (int k = j + 1; k < n; ++k) { - x[j][i] -= a[index[j]][k] * x[k][i]; - } - x[j][i] /= a[index[j]][j]; - } - } - return x; - } - - // Method to carry out the partial-pivoting Gaussian - // elimination. Here index[] stores pivoting order. - private void gaussian(double a[][], int index[]) { - int n = index.length; - double c[] = new double[n]; - // Initialize the index - for (int i = 0; i < n; ++i) { - index[i] = i; - } - // Find the rescaling factors, one from each row - for (int i = 0; i < n; ++i) { - double c1 = 0; - for (int j = 0; j < n; ++j) { - double c0 = Math.abs(a[i][j]); - if (c0 > c1) { - c1 = c0; - } - } - c[i] = c1; - } - - // Search the pivoting element from each column - int k = 0; - for (int j = 0; j < n - 1; ++j) { - double pi1 = 0; - for (int i = j; i < n; ++i) { - double pi0 = Math.abs(a[index[i]][j]); - pi0 /= c[index[i]]; - if (pi0 > pi1) { - pi1 = pi0; - k = i; - } - } - - // Interchange rows according to the pivoting order - int itmp = index[j]; - index[j] = index[k]; - index[k] = itmp; - for (int i = j + 1; i < n; ++i) { - double pj = a[index[i]][j] / a[index[j]][j]; - // Record pivoting ratios below the diagonal - a[index[i]][j] = pj; - // Modify other elements accordingly - for (int l = j + 1; l < n; ++l) { - a[index[i]][l] -= pj * a[index[j]][l]; - } - } - } - } - - /** - * Get all prime factors of input number. - * - * @param n An integer number. - * @return Array of primes. - * - * Thanks to - * http://www.javacodegeeks.com/2014/05/how-to-find-prime-factors-of-integer-numbers-in-java-factorization.html - * and http://stackoverflow.com/a/2451219/2534036 - */ - public long[] factor(long n) { - long i; - Set primes = new HashSet<>(); - long copyOfInput = n; - - for (i = 2; i <= copyOfInput; i++) { - if (copyOfInput % i == 0) { - primes.add(i); // prime factor - copyOfInput /= i; - i--; - } - } - long[] a = new long[primes.size()]; - int j = 0; - for (Object val : primes) { - a[j++] = (long) val; - } - return a; - } - - public boolean isprime(long n) { - int i = 2; - while (i <= sqrt(n)) { - if (n % i == 0) { - return false; - } - i++; - } - return true; - } - - public boolean isprime(String nn) { - BigInteger n = new BigInteger(nn); - BigInteger i = new BigInteger("2"); - BigInteger ns = bigIntSqRootCeil(n); - while (i.compareTo(ns) <= 0) { - if (n.mod(i).toString().equals("0")) { - return false; - } - i = i.add(BigInteger.ONE); - } - return true; - } - - /** - * Thanks to http://stackoverflow.com/a/11962756/2534036 - * - * @param x - * @return - * @throws IllegalArgumentException - */ - private BigInteger bigIntSqRootCeil(BigInteger x) throws IllegalArgumentException { - if (x.compareTo(BigInteger.ZERO) < 0) { - throw new IllegalArgumentException("Negative argument."); - } - // square roots of 0 and 1 are trivial and - // y == 0 will cause a divide-by-zero exception - if (x == BigInteger.ZERO || x == BigInteger.ONE) { - return x; - } // end if - BigInteger two = BigInteger.valueOf(2L); - BigInteger y; - // starting with y = x / 2 avoids magnitude issues with x squared - for (y = x.divide(two); y.compareTo(x.divide(y)) > 0; y = ((x.divide(y)).add(y)).divide(two)) { - } - if (x.compareTo(y.multiply(y)) == 0) { - return y; - } else { - return y.add(BigInteger.ONE); - } - - } // end bigIntSqRootCeil - - /** - * Get all unique permutations of the given array. - * - * @param objs Array of items. - * @return Matrix - */ - public Object[] perms(Object... objs) { - Permutations perm = new Permutations<>(objs); - - Set perms = new HashSet<>(); - - while (perm.hasNext()) { - perms.add(perm.next()); - } - - Object[][] a = new Object[perms.size()][objs.length]; - return perms.toArray(a); - } - - /** - * Get a uniform random fraction between 0.0 (inclusive) and 1.0 - * (exclusive). - * - * @return random fraction - */ - public double rand() { - return rng.nextDouble(); - } - - /** - * Get a random boolean value. - * - * @return true or false - */ - public boolean randb() { - return rng.nextBoolean(); - } - - /** - * Get a uniform random integer. - * - * @param min Minimum value, inclusive - * @param max Maximum value, inclusive - * @return random integer - */ - public double rand(int min, int max) { - if (min == 0 && max == 0) { - return rand(); - } - return rng.nextInt((max - min) + 1) + min; - } - - /** - * Multiply two matrices. - * - * @param a First matrix - * @param b Second matrix - * @return The multiplied matrices - * @throws net.apocalypselabs.symat.BadInputException When the matrices are - * wrong. - */ - public double[][] mtimes(double[][] a, double[][] b) throws BadInputException { - double[][] ans = new double[a.length][b[0].length]; - double sum = 0; - int c, d, k, m = a.length, q = b[0].length, p = b.length; - - if (a[0].length != b.length) { - throw new BadInputException("First matrix column count must match " - + "second matrix row count."); - } - - for (c = 0; c < m; c++) { - for (d = 0; d < q; d++) { - for (k = 0; k < p; k++) { - sum = sum + a[c][k] * b[k][d]; - } - ans[c][d] = sum; - sum = 0; - } - } - return ans; - } - - /** - * Multiply the given matrix by itself b times. - * - * @param a Square matrix - * @param b Power ( >= 0 ) - * @return The matrix result - * @throws BadInputException if the matrix is not square or power is less - * than 0 - */ - public double[][] mpower(double[][] a, int b) throws BadInputException { - if (a.length != a[0].length) { - throw new BadInputException("Matrix needs to be square."); - } - if (b < 0) { - throw new BadInputException("Power cannot be negative."); - } - - double[][] ans = a; - - for (int i = 0; i < b; i++) { - if (i == 0) { - ans = a; - } else { - ans = mtimes(a, ans); - } - } - return ans; - } - - /** - * Convert the given number of degrees to radians. - * - * @param degrees Number in degrees - * @return Radians (degrees * (pi/180)) - */ - public double rad(double degrees) { - return degrees * (PI / 180); - } - - /** - * Convert the given number of radians to degrees. - * - * @param radians Number in radians - * @return Degrees (radians * (180/pi)) - */ - public double deg(double radians) { - return radians * (180 / PI); - } - - public String sym(String input) { - return util.evaluate(input).toString(); - } - - /** - * Evaluate the given text with the builtin Symja parser. - * - * @param input - * @return - */ - public String $(String input) { - return sym(input); - } - - /** - * Replace all occurrences of variable with newvar in function. - * - * @param function Text input - * @param variable Text to replace - * @param newvar Text to replace with - * @return function with text replaced. - */ - public String replace(String function, String variable, String newvar) { - return function.replaceAll(variable, newvar); - } - - /** - * Substitute newvar for variable in function and attempt to calculate a - * numerical answer. - *
Example: subs('32*x','x',2) = 64.0 - * - * @param function Function - * @param variable Variable to substitute - * @param newvar Value to replace with - * @return The numerical answer or zero if there is no numerical answer. - */ - public double subs(String function, String variable, String newvar) { - return numof(function.replaceAll(variable, newvar)); - } - - /** - * Attempt to find numerical value of input. - * - * @param f Function - * @return answer or zero if it doesn't exist - */ - public double numof(String f) { - try { - return Double.parseDouble(util.evaluate("N(" + f + ")").toString()); - } catch (MathException | NumberFormatException ex) { - return 0.0; - } - } - - /* - Graphing interfaces - */ - public void xlim(double xmin, double xmax) { - graphwin.setRange(xmin, xmax); - } - - public void plot(String function) { - showGraph(); - if (!function.equals("")) { - graphwin.graphFunction(function); - } - } - - public void plot(double[] x, double[] y) { - graphwin.plotPoints(x, y); - } - - public void plot(double[] x, double[] y, String name) { - graphwin.plotPoints(x, y, name); - } - - public void plot(String function, double xmin, double xmax) { - graphwin.setRange(xmin, xmax); - plot(function); - } - - public void ezplot(String f) { - plot(f); - } - - public void ezplot(String function, double xmin, double xmax) { - plot(function, xmin, xmax); - } - - public void graph(String f) { - plot(f); - } - - public String plotname() { - return graphwin.getTitle(); - } - - public String plotname(String t) { - if (t.equals("symatpythonnullplotname")) { - return graphwin.getTitle(); - } else { - graphwin.setWindowTitle(t); - graphwin.setLabel(t); - return ""; - } - } - - public void plot() { - showGraph(); - } - - public void plotclr() { - graphwin.clearDraw(); - } - - public void clearplot() { - plotclr(); - } - - public void plotclear() { - plotclr(); - } - - public void drawdot(double x, double y) { - showGraph(); - graphwin.drawDot(x, y); - } - - public String readfile(String path) throws IOException { - return FileUtils.readFile(path); - } - - public void savefile(String content, String path) throws IOException { - FileUtils.saveFile(content, path, false); - } - - /** - * Show a file dialog and return the path of the chosen file (or "" if - * canceled). - * - * @return - */ - public String filedialog() { - JFileChooser fc = new JFileChooser(); - int result = fc.showDialog(Main.maingui, "Choose"); - if (result == JFileChooser.APPROVE_OPTION) { - return fc.getSelectedFile().getPath(); - } - return ""; - } - - public String md5sum(String data) { - return FileUtils.MD5(data); - } - - public void save(String key, String val) { - Preferences prefs = Preferences.userNodeForPackage(Functions.class); - prefs.put(key, val); - try { - prefs.flush(); - } catch (Exception ex) { - - } - } - - public String load(String key) { - Preferences prefs = Preferences.userNodeForPackage(Functions.class); - return prefs.get(key, ""); - } - - /* - Other - */ - public String sysinfo() { - String info = "==Java Information==\n"; - info += "Java version: " + System.getProperty("java.version"); - info += "\nJava vendor: " + System.getProperty("java.vendor"); - info += "\nJava home: " + System.getProperty("java.home"); - - return info; - } - - /** - * Reset the license, quit the application. - */ - public void resetlicense() { - int result = JOptionPane.showConfirmDialog(null, - "Are you sure you want to reset your license?\n" - + "This will close SyMAT and all open files!", - "Reset license", - JOptionPane.YES_NO_CANCEL_OPTION, - JOptionPane.QUESTION_MESSAGE); - if (result == JOptionPane.YES_OPTION) { - PrefStorage.unset("license"); - System.exit(0); - } - } - - public String license() { - String expires = "Error"; - if (PrefStorage.getSetting("licensetype").equals("demo")) { - Calendar c = Calendar.getInstance(); - c.setTime(new Date()); - try { - long expire = Long.parseLong(PrefStorage.getSetting("license")); - long days = (((expire - c.getTimeInMillis()) / (60 * 60 * 24)) - 999) / 1000; - if (days < 0) { - if (days == -1) { - expires = "Today"; - } else { - expires = abs(days) + " days ago"; - } - } else { - expires = "In " + days + " days"; - } - } catch (NumberFormatException e) { - } - } else { - try { - URL url = new URL(API_URL + "expire.php?email=" + PrefStorage.getSetting("license")); - try (InputStream is = url.openStream(); - BufferedReader br - = new BufferedReader(new InputStreamReader(is))) { - expires = br.readLine(); - } catch (IOException ex) { - } - } catch (Exception ex) { - } - } - String lic = "==License Information==\n" - + "License: " + PrefStorage.getSetting("license") - + "\nType: " + PrefStorage.getSetting("licensetype") - + "\nExpires: " + expires; - return lic; - } - - /** - * Make sure the graph window shows. - */ - private void showGraph() { - graphwin.setVisible(true); - graphwin.toFront(); - } - - public TextBox textbox() { - return new TextBox(); - } - - public WebBrowser browser() { - return new WebBrowser(); - } - /* - Constructor. - */ - - public Functions() { - Main.loadFrame(graphwin, false); - } - - public void setLang(String l) { - lang = l; - } - - /** - * This class finds permutations of an array. - * - * Credit to http://stackoverflow.com/a/14444037/2534036 - * - * License: CC-BY-SA 3.0 - * - * @param - */ - class Permutations implements Iterator { - - private final E[] arr; - private final int[] ind; - private boolean has_next; - - public E[] output;//next() returns this array, make it public - - Permutations(E[] arr) { - this.arr = arr.clone(); - ind = new int[arr.length]; - //convert an array of any elements into array of integers - first occurrence is used to enumerate - Map hm = new HashMap<>(); - for (int i = 0; i < arr.length; i++) { - Integer n = hm.get(arr[i]); - if (n == null) { - hm.put(arr[i], i); - n = i; - } - ind[i] = n; - } - Arrays.sort(ind);//start with ascending sequence of integers - - //output = new E[arr.length]; <-- cannot do in Java with generics, so use reflection - output = (E[]) Array.newInstance(arr.getClass().getComponentType(), arr.length); - has_next = true; - } - - @Override - public boolean hasNext() { - return has_next; - } - - /** - * Computes next permutations. Same array instance is returned every - * time! - * - * @return - */ - @Override - public E[] next() { - if (!has_next) { - throw new NoSuchElementException(); - } - - for (int i = 0; i < ind.length; i++) { - output[i] = arr[ind[i]]; - } - - //get next permutation - has_next = false; - for (int tail = ind.length - 1; tail > 0; tail--) { - if (ind[tail - 1] < ind[tail]) {//still increasing - - //find last element which does not exceed ind[tail-1] - int s = ind.length - 1; - while (ind[tail - 1] >= ind[s]) { - s--; - } - - swap(ind, tail - 1, s); - - //reverse order of elements in the tail - for (int i = tail, j = ind.length - 1; i < j; i++, j--) { - swap(ind, i, j); - } - has_next = true; - break; - } - - } - return output; - } - - private void swap(int[] arr, int i, int j) { - int t = arr[i]; - arr[i] = arr[j]; - arr[j] = t; - } - - @Override - public void remove() { - - } - } -} +/* + * CODE LICENSE ===================== + * Copyright (c) 2015, Apocalypse Laboratories + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * 4. You adhere to the Media License detailed below. If you do not, this license + * is automatically revoked and you must purge all copies of the software you + * possess, in source or binary form. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * MEDIA LICENSE ==================== + * All images and other graphical files (the "graphics") included with this + * software are copyright (c) 2015 Apocalypse Laboratories. You may not distribute + * the graphics or any program, source code repository, or other digital storage + * media containing them without written permission from Apocalypse Laboratories. + * This ban on distribution only applies to publicly available systems. + * A password-protected network file share, USB drive, or other storage scheme that + * cannot be easily accessed by the public is generally allowed. If in doubt, + * contact Apocalypse Laboratories. If Apocalypse Laboratories allows or denies + * you permission, that decision is considered final and binding. + */ +package net.apocalypselabs.symat; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import static java.lang.Math.*; +import java.lang.reflect.Array; +import java.math.BigInteger; +import java.net.URL; +import java.security.SecureRandom; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; +import java.util.prefs.Preferences; +import javax.swing.JFileChooser; +import javax.swing.JOptionPane; +import static net.apocalypselabs.symat.Main.API_URL; +import net.apocalypselabs.symat.components.TextBox; +import org.matheclipse.core.eval.EvalUtilities; +import org.matheclipse.core.interfaces.IExpr; +import org.matheclipse.parser.client.math.MathException; +import org.mozilla.javascript.NativeArray; +import org.python.core.PyList; + +/** + * These functions are accessible from JavaScript. + * + * There are a lot of aliases in here too. + * + * @author Skylar + */ +public class Functions { + + public static final HashMap GLOBALS = new HashMap<>(); + + private final EvalUtilities util = new EvalUtilities(true, true); + Graph graphwin = new Graph(true); + + private String lang = "py"; + + private final SecureRandom rng = new SecureRandom(); + + /* + Useful interactions + */ + /** + * Display a message dialog box. + * + * @param message The message to give. + */ + public void notify(Object message) { + JOptionPane.showInternalMessageDialog(Main.mainPane, message.toString()); + } + + /** + * Display message dialog. + * + * This is an alias to help JavaScript programmers. + * + * @param message The message + */ + public void alert(Object message) { + notify(message); + } + + /** + * Display an input dialog box with a text field. + * + * @param question Text to label dialog + * @return The inputted text + */ + public String ask(String question) { + return JOptionPane.showInternalInputDialog(Main.mainPane, question); + } + + /** + * Pause execution for the specified number of milliseconds. + * + * @param millis + */ + public void pause(long millis) { + try { + Thread.sleep(millis); + } catch (InterruptedException e) { + // Nothing to do. + } + } + + /** + * @see pause() + * @param millis + */ + public void sleep(long millis) { + pause(millis); + } + + /** + * Quit SyMAT. + */ + public void quitApplication() { + System.exit(0); + } + + /* + Math commands + */ + /** + * Find the factorial (n!) of a number. + * + * @param n positive integer + * @return n! as String + * @throws net.apocalypselabs.symat.BadInputException + */ + public String factorial(long n) throws BadInputException { + if (n <= 0) { + throw new BadInputException("Input must be greater than zero!"); + } + + BigInteger inc = new BigInteger("1"); + BigInteger fact = new BigInteger("1"); + + for (long c = 1; c <= n; c++) { + fact = fact.multiply(inc); + inc = inc.add(BigInteger.ONE); + } + return fact.toString(); + } + + /** + * Take (a^b) mod m. If b is -1, finds the modular inverse of a mod m. + * + * @param a Number + * @param b Exponent + * @param m Modulus + * @return pow(a,b)%m. + */ + public double powermod(double a, double b, double m) { + if (b == -1) { + BigInteger in = new BigInteger(String.valueOf((int) a)); + return in.modInverse(new BigInteger(String.valueOf((int) m))).doubleValue(); + } + return (pow(a, b) % m + m) % m; + } + + /** + * Take (a^b) mod m. If b is -1, finds the modular inverse of a mod m. + * + * @param a Number + * @param b Exponent + * @param m Modulus + * @return pow(a,b)%m. + */ + public String powermod(String a, String b, String m) { + BigInteger in = new BigInteger(a); + if (b.equals("-1")) { + return in.modInverse(new BigInteger(m)).toString(); + } + return in.modPow(new BigInteger(b), new BigInteger(m)).toString(); + } + + public long gcd(long a, long b) { + if (b == 0) { + return a; + } + return gcd(b, a % b); + } + + public String gcd(String a, String b) { + return (new BigInteger(a).gcd(new BigInteger(b)).toString()); + } + + /** + * Differentiate the function with respect to idv. + * + * @param function Function + * @param idv independent variable + * @return Differentiated function + */ + public String diff(String function, String idv) { + return util.evaluate("diff(" + function + "," + idv + ")").toString(); + } + + /** + * Differentiate the function with respect to x. + * + * @param function Function + * @return Differentiated function + */ + public String diff(String function) { + // Assume "x" as var + return diff(function, "x"); + } + + @Deprecated + public String D(String function, String idv) { + return diff(function, idv); + } + + public double[] solve(String function, String idv, int eq) { + String res = $("Solve[" + function + "==" + eq + ", " + idv + "]"); + res = res.substring(1, res.length() - 1); + String[] cmp = res.split(","); + for (int i = 0; i < cmp.length; i++) { + cmp[i] = cmp[i].replace("{" + idv + "->", ""); + cmp[i] = cmp[i].replace("}", ""); + } + double[] out = new double[cmp.length]; + for (int i = 0; i < cmp.length; i++) { + try { + if (cmp[i].contains("I")) { + if (cmp[i].contains("-I")) { + out[i] = Double.NEGATIVE_INFINITY; + } else { + out[i] = Double.POSITIVE_INFINITY; + } + } else { + out[i] = Double.parseDouble(cmp[i]); + } + } catch (Exception ex) { + return new double[]{Double.NaN}; + } + } + return out; + } + + public double[] solve(String function, String idv) { + return solve(function, idv, 0); + } + + public double[] solve(String function) { + return solve(function, "x"); + } + + private String printa(double[] o) { + String out = "["; + for (int i = 0; i < o.length; i++) { + out += o[i] + (i == o.length - 1 ? "" : ", "); + } + out += "]"; + return out; + } + + private String printa(int[] o) { + String out = "["; + for (int i = 0; i < o.length; i++) { + out += o[i] + (i == o.length - 1 ? "" : ", "); + } + out += "]"; + return out; + } + + private String printa(boolean[] o) { + String out = "["; + for (int i = 0; i < o.length; i++) { + out += (o[i] ? "true" : "false") + (i == o.length - 1 ? "" : ", "); + } + out += "]"; + return out; + } + + public String printa(Object o) { + String out = "["; + if (o instanceof int[]) { + int[] arr = (int[]) o; + for (int i = 0; i < arr.length; i++) { + out += arr[i] + (i == arr.length - 1 ? "" : ", "); + } + } else if (o instanceof double[]) { + double[] arr = (double[]) o; + for (int i = 0; i < arr.length; i++) { + out += arr[i] + (i == arr.length - 1 ? "" : ", "); + } + } else if (o instanceof boolean[]) { + double[] arr = (double[]) o; + for (int i = 0; i < arr.length; i++) { + out += arr[i] + (i == arr.length - 1 ? "" : ", "); + } + } else if (o instanceof int[][]) { + int[][] arr = (int[][]) o; + for (int i = 0; i < arr.length; i++) { + out += printa(arr[i]) + (i == arr.length - 1 ? "" : ", "); + } + } else if (o instanceof double[][]) { + double[][] arr = (double[][]) o; + for (int i = 0; i < arr.length; i++) { + out += printa(arr[i]) + (i == arr.length - 1 ? "" : ", "); + } + } else if (o instanceof boolean[][]) { + boolean[][] arr = (boolean[][]) o; + for (int i = 0; i < arr.length; i++) { + out += printa(arr[i]) + (i == arr.length - 1 ? "" : ", "); + } + } else if (o instanceof NativeArray) { + NativeArray arr = (NativeArray) o; + for (long i = 0; i < arr.getLength(); i++) { + + out += (arr.get(i) instanceof NativeArray ? printa(arr.get(i)) + : arr.get(i).toString()) + + (i == arr.getLength() - 1 ? "" : ", "); + } + } else if (o instanceof PyList) { + PyList arr = (PyList) o; + Object[] oo = arr.toArray(); + for (int i = 0; i < oo.length; i++) { + out += (oo[i] instanceof Object[] ? printa(oo[i]) : oo[i].toString()) + + (i == oo.length - 1 ? "" : ", "); + } + } else { + Object[] arr = (Object[]) o; + for (int i = 0; i < arr.length; i++) { + out += (arr[i] instanceof Object[] ? printa(arr[i]) : arr[i].toString()) + + (i == arr.length - 1 ? "" : ", "); + } + } + out += "]"; + return out; + } + + /** + * Integrate the function with respect to idv. + * + * @param function Function + * @param idv independent variable + * @return Integrated function + */ + public String integrate(String function, String idv) { + return util.evaluate("integrate(" + function + "," + idv + ")").toString(); + } + + /** + * Integrate the function with respect to x. + * + * @param function Function + * @return Integrated function + */ + public String integrate(String function) { + return integrate(function, "x"); + } + + public String factor(String function) { + return sym("Factor(" + function + ")"); + } + + /** + * Simplify the given expression. + * + * @param expr expression + * @return simplified expression + */ + public String simplify(String expr) { + return sym("Simplify(" + expr + ")"); + } + + public Object vpa(String expr) { + IExpr ans = util.evaluate("N(" + expr + ")"); + if (ans.isNumber()) { + return Double.parseDouble(ans.toString()); + } + return ans.toString(); + } + + public int[] primes(int in) { + boolean[] prime = new boolean[in]; + for (int i = 0; i < prime.length; i++) { + prime[i] = true; + } + for (int i = 2; i < sqrt(in); i++) { + if (prime[i]) { + int x = 0; + for (int j = i * i; j < in; j = i * i + x * i) { + prime[j] = false; + x++; + } + } + } + List arr = new ArrayList<>(); + for (int i = 2; i < prime.length; i++) { + if (prime[i]) { + arr.add(i); + } + } + int[] out = new int[arr.size()]; + for (int i = 0; i < arr.size(); i++) { + out[i] = arr.get(i); + } + return out; + } + + public double sec(double d) { + return 1.0 / Math.cos(d); + } + + public double csc(double d) { + return 1.0 / Math.sin(d); + } + + public double cot(double d) { + return 1.0 / Math.tan(d); + } + + public double asec(double d) { + return Math.acos(1.0 / d); + } + + public double acsc(double d) { + return Math.asin(1.0 / d); + } + + public double acot(double d) { + return Math.atan(1.0 / d); + } + + public double sinh(double d) { + return Math.sinh(d); + } + + public double cosh(double d) { + return Math.cosh(d); + } + + public double tanh(double d) { + return Math.tanh(d); + } + + public double sech(double d) { + return pow(Math.cosh(d), -1); + } + + public double csch(double d) { + return pow(Math.sinh(d), -1); + } + + public double coth(double d) { + return Math.cosh(d) / Math.sinh(d); + } + + /** + * Multiplies the given numbers together. + * + * @param a numbers. Calculates first * second * third, etc. + * @return The product of the numbers or the value of input if there is only + * one input. + */ + public double times(double... a) { + double ans = 0; + for (int i = 0; i < a.length; i++) { + if (i == 0) { + ans = a[i]; + } else { + ans *= a[i]; + } + } + return ans; + } + + /** + * Multiplies the given numbers together. + * + * @param a + * @param b + * @return The product of the numbers or the value of input if there is only + * one input. + */ + public String times(String a, String b) { + return (new BigInteger(a).multiply(new BigInteger(b))).toString(); + } + + /** + * Divide the given numbers. + * + * @param a numbers. Calculates (first / second) / third, etc. + * @return The quotient of the numbers or the value of input if there is + * only one input. + */ + public double divide(double... a) { + double ans = 0; + for (int i = 0; i < a.length; i++) { + if (i == 0) { + ans = a[i]; + } else { + ans /= a[i]; + } + } + return ans; + } + + /** + * Divide the given numbers. + * + * @param a + * @param b + * @return The quotient of the numbers or the value of input if there is + * only one input. + */ + public String divide(String a, String b) { + return (new BigInteger(a).divide(new BigInteger(b))).toString(); + } + + /** + * Divide the first number by the second and return the remainder. + * + * @param a numbers. Calculates (first mod second) mod third, etc. + * @return The modulus of the numbers or the value of input if there is only + * one input. + */ + public double mod(double... a) { + double ans = 0; + for (int i = 0; i < a.length; i++) { + if (i == 0) { + ans = a[i]; + } else { + ans %= a[i]; + } + } + return ans; + } + + /** + * Divide the first number by the second and return the remainder. + * + * @param a + * @param b + * @return The modulus of the numbers or the value of input if there is only + * one input. + */ + public String mod(String a, String b) { + return (new BigInteger(a).mod(new BigInteger(b))).toString(); + } + + /** + * Add the given numbers together. + * + * @param a numbers. Calculates first + second + third, etc. + * @return The sum of the numbers or the value of input if there is only one + * input. + */ + public double add(double... a) { + double ans = 0; + for (double d : a) { + ans += d; + } + return ans; + } + + /** + * Add the given numbers together. + * + * @param a numbers. Calculates first + second + third, etc. + * @return The sum of the numbers or the value of input if there is only one + * input. + */ + public String add(String a, String b) { + return (new BigInteger(a).subtract(new BigInteger(b))).toString(); + } + + /** + * Subtract the given numbers. + * + * @param a numbers. Calculates (first - second) - third, etc. + * @return The difference of the numbers or the value of input if there is + * only one input. + */ + public double subtract(double... a) { + double ans = 0; + for (int i = 0; i < a.length; i++) { + if (i == 0) { + ans = a[i]; + } else { + ans -= a[i]; + } + } + return ans; + } + + /** + * Subtract the given numbers. + * + * @param a numbers. Calculates (first - second) - third, etc. + * @return The difference of the numbers or the value of input if there is + * only one input. + */ + public String subtract(String a, String b) { + BigInteger ans = new BigInteger(a); + ans = ans.subtract(new BigInteger(b)); + return ans.toString(); + } + + public double[][] minvert(double a[][]) { + int n = a.length; + double x[][] = new double[n][n]; + double b[][] = new double[n][n]; + int index[] = new int[n]; + for (int i = 0; i < n; ++i) { + b[i][i] = 1; + } + // Transform the matrix into an upper triangle + gaussian(a, index); + // Update the matrix b[i][j] with the ratios stored + for (int i = 0; i < n - 1; ++i) { + for (int j = i + 1; j < n; ++j) { + for (int k = 0; k < n; ++k) { + b[index[j]][k] + -= a[index[j]][i] * b[index[i]][k]; + } + } + } + // Perform backward substitutions + for (int i = 0; i < n; ++i) { + x[n - 1][i] = b[index[n - 1]][i] / a[index[n - 1]][n - 1]; + for (int j = n - 2; j >= 0; --j) { + x[j][i] = b[index[j]][i]; + for (int k = j + 1; k < n; ++k) { + x[j][i] -= a[index[j]][k] * x[k][i]; + } + x[j][i] /= a[index[j]][j]; + } + } + return x; + } + + // Method to carry out the partial-pivoting Gaussian + // elimination. Here index[] stores pivoting order. + private void gaussian(double a[][], int index[]) { + int n = index.length; + double c[] = new double[n]; + // Initialize the index + for (int i = 0; i < n; ++i) { + index[i] = i; + } + // Find the rescaling factors, one from each row + for (int i = 0; i < n; ++i) { + double c1 = 0; + for (int j = 0; j < n; ++j) { + double c0 = Math.abs(a[i][j]); + if (c0 > c1) { + c1 = c0; + } + } + c[i] = c1; + } + + // Search the pivoting element from each column + int k = 0; + for (int j = 0; j < n - 1; ++j) { + double pi1 = 0; + for (int i = j; i < n; ++i) { + double pi0 = Math.abs(a[index[i]][j]); + pi0 /= c[index[i]]; + if (pi0 > pi1) { + pi1 = pi0; + k = i; + } + } + + // Interchange rows according to the pivoting order + int itmp = index[j]; + index[j] = index[k]; + index[k] = itmp; + for (int i = j + 1; i < n; ++i) { + double pj = a[index[i]][j] / a[index[j]][j]; + // Record pivoting ratios below the diagonal + a[index[i]][j] = pj; + // Modify other elements accordingly + for (int l = j + 1; l < n; ++l) { + a[index[i]][l] -= pj * a[index[j]][l]; + } + } + } + } + + /** + * Get all prime factors of input number. + * + * @param n An integer number. + * @return Array of primes. + * + * Thanks to + * http://www.javacodegeeks.com/2014/05/how-to-find-prime-factors-of-integer-numbers-in-java-factorization.html + * and http://stackoverflow.com/a/2451219/2534036 + */ + public long[] factor(long n) { + long i; + Set primes = new HashSet<>(); + long copyOfInput = n; + + for (i = 2; i <= copyOfInput; i++) { + if (copyOfInput % i == 0) { + primes.add(i); // prime factor + copyOfInput /= i; + i--; + } + } + long[] a = new long[primes.size()]; + int j = 0; + for (Object val : primes) { + a[j++] = (long) val; + } + return a; + } + + public boolean isprime(long n) { + int i = 2; + while (i <= sqrt(n)) { + if (n % i == 0) { + return false; + } + i++; + } + return true; + } + + public boolean isprime(String nn) { + BigInteger n = new BigInteger(nn); + BigInteger i = new BigInteger("2"); + BigInteger ns = bigIntSqRootCeil(n); + while (i.compareTo(ns) <= 0) { + if (n.mod(i).toString().equals("0")) { + return false; + } + i = i.add(BigInteger.ONE); + } + return true; + } + + /** + * Thanks to http://stackoverflow.com/a/11962756/2534036 + * + * @param x + * @return + * @throws IllegalArgumentException + */ + private BigInteger bigIntSqRootCeil(BigInteger x) throws IllegalArgumentException { + if (x.compareTo(BigInteger.ZERO) < 0) { + throw new IllegalArgumentException("Negative argument."); + } + // square roots of 0 and 1 are trivial and + // y == 0 will cause a divide-by-zero exception + if (x == BigInteger.ZERO || x == BigInteger.ONE) { + return x; + } // end if + BigInteger two = BigInteger.valueOf(2L); + BigInteger y; + // starting with y = x / 2 avoids magnitude issues with x squared + for (y = x.divide(two); y.compareTo(x.divide(y)) > 0; y = ((x.divide(y)).add(y)).divide(two)) { + } + if (x.compareTo(y.multiply(y)) == 0) { + return y; + } else { + return y.add(BigInteger.ONE); + } + + } // end bigIntSqRootCeil + + /** + * Get all unique permutations of the given array. + * + * @param objs Array of items. + * @return Matrix + */ + public Object[] perms(Object... objs) { + Permutations perm = new Permutations<>(objs); + + Set perms = new HashSet<>(); + + while (perm.hasNext()) { + perms.add(perm.next()); + } + + Object[][] a = new Object[perms.size()][objs.length]; + return perms.toArray(a); + } + + /** + * Get a uniform random fraction between 0.0 (inclusive) and 1.0 + * (exclusive). + * + * @return random fraction + */ + public double rand() { + return rng.nextDouble(); + } + + /** + * Get a random boolean value. + * + * @return true or false + */ + public boolean randb() { + return rng.nextBoolean(); + } + + /** + * Get a uniform random integer. + * + * @param min Minimum value, inclusive + * @param max Maximum value, inclusive + * @return random integer + */ + public double rand(int min, int max) { + if (min == 0 && max == 0) { + return rand(); + } + return rng.nextInt((max - min) + 1) + min; + } + + /** + * Multiply two matrices. + * + * @param a First matrix + * @param b Second matrix + * @return The multiplied matrices + * @throws net.apocalypselabs.symat.BadInputException When the matrices are + * wrong. + */ + public double[][] mtimes(double[][] a, double[][] b) throws BadInputException { + double[][] ans = new double[a.length][b[0].length]; + double sum = 0; + int c, d, k, m = a.length, q = b[0].length, p = b.length; + + if (a[0].length != b.length) { + throw new BadInputException("First matrix column count must match " + + "second matrix row count."); + } + + for (c = 0; c < m; c++) { + for (d = 0; d < q; d++) { + for (k = 0; k < p; k++) { + sum = sum + a[c][k] * b[k][d]; + } + ans[c][d] = sum; + sum = 0; + } + } + return ans; + } + + /** + * Multiply the given matrix by itself b times. + * + * @param a Square matrix + * @param b Power ( >= 0 ) + * @return The matrix result + * @throws BadInputException if the matrix is not square or power is less + * than 0 + */ + public double[][] mpower(double[][] a, int b) throws BadInputException { + if (a.length != a[0].length) { + throw new BadInputException("Matrix needs to be square."); + } + if (b < 0) { + throw new BadInputException("Power cannot be negative."); + } + + double[][] ans = a; + + for (int i = 0; i < b; i++) { + if (i == 0) { + ans = a; + } else { + ans = mtimes(a, ans); + } + } + return ans; + } + + /** + * Convert the given number of degrees to radians. + * + * @param degrees Number in degrees + * @return Radians (degrees * (pi/180)) + */ + public double rad(double degrees) { + return degrees * (PI / 180); + } + + /** + * Convert the given number of radians to degrees. + * + * @param radians Number in radians + * @return Degrees (radians * (180/pi)) + */ + public double deg(double radians) { + return radians * (180 / PI); + } + + public String sym(String input) { + return util.evaluate(input).toString(); + } + + /** + * Evaluate the given text with the builtin Symja parser. + * + * @param input + * @return + */ + public String $(String input) { + return sym(input); + } + + /** + * Replace all occurrences of variable with newvar in function. + * + * @param function Text input + * @param variable Text to replace + * @param newvar Text to replace with + * @return function with text replaced. + */ + public String replace(String function, String variable, String newvar) { + return function.replaceAll(variable, newvar); + } + + /** + * Substitute newvar for variable in function and attempt to calculate a + * numerical answer. + *
Example: subs('32*x','x',2) = 64.0 + * + * @param function Function + * @param variable Variable to substitute + * @param newvar Value to replace with + * @return The numerical answer or zero if there is no numerical answer. + */ + public double subs(String function, String variable, String newvar) { + return numof(function.replaceAll(variable, newvar)); + } + + /** + * Attempt to find numerical value of input. + * + * @param f Function + * @return answer or zero if it doesn't exist + */ + public double numof(String f) { + try { + return Double.parseDouble(util.evaluate("N(" + f + ")").toString()); + } catch (MathException | NumberFormatException ex) { + return 0.0; + } + } + + /* + Graphing interfaces + */ + public void xlim(double xmin, double xmax) { + graphwin.setRange(xmin, xmax); + } + + public void plot(String function) { + showGraph(); + if (!function.equals("")) { + graphwin.graphFunction(function); + } + } + + public void plot(double[] x, double[] y) { + graphwin.plotPoints(x, y); + } + + public void plot(double[] x, double[] y, String name) { + graphwin.plotPoints(x, y, name); + } + + public void plot(String function, double xmin, double xmax) { + graphwin.setRange(xmin, xmax); + plot(function); + } + + public void ezplot(String f) { + plot(f); + } + + public void ezplot(String function, double xmin, double xmax) { + plot(function, xmin, xmax); + } + + public void graph(String f) { + plot(f); + } + + public String plotname() { + return graphwin.getTitle(); + } + + public String plotname(String t) { + if (t.equals("symatpythonnullplotname")) { + return graphwin.getTitle(); + } else { + graphwin.setWindowTitle(t); + graphwin.setLabel(t); + return ""; + } + } + + public void plot() { + showGraph(); + } + + public void plotclr() { + graphwin.clearDraw(); + } + + public void clearplot() { + plotclr(); + } + + public void plotclear() { + plotclr(); + } + + public void drawdot(double x, double y) { + showGraph(); + graphwin.drawDot(x, y); + } + + public String readfile(String path) throws IOException { + return FileUtils.readFile(path); + } + + public void savefile(String content, String path) throws IOException { + FileUtils.saveFile(content, path, false); + } + + /** + * Show a file dialog and return the path of the chosen file (or "" if + * canceled). + * + * @return + */ + public String filedialog() { + JFileChooser fc = new JFileChooser(); + int result = fc.showDialog(Main.maingui, "Choose"); + if (result == JFileChooser.APPROVE_OPTION) { + return fc.getSelectedFile().getPath(); + } + return ""; + } + + public String md5sum(String data) { + return FileUtils.MD5(data); + } + + public void save(String key, String val) { + Preferences prefs = Preferences.userNodeForPackage(Functions.class); + prefs.put(key, val); + try { + prefs.flush(); + } catch (Exception ex) { + + } + } + + public String load(String key) { + Preferences prefs = Preferences.userNodeForPackage(Functions.class); + return prefs.get(key, ""); + } + + /* + Other + */ + public String sysinfo() { + String info = "==Java Information==\n"; + info += "Java version: " + System.getProperty("java.version"); + info += "\nJava vendor: " + System.getProperty("java.vendor"); + info += "\nJava home: " + System.getProperty("java.home"); + + return info; + } + + /** + * Reset the license, quit the application. + */ + public void resetlicense() { + int result = JOptionPane.showConfirmDialog(null, + "Are you sure you want to reset your license?\n" + + "This will close SyMAT and all open files!", + "Reset license", + JOptionPane.YES_NO_CANCEL_OPTION, + JOptionPane.QUESTION_MESSAGE); + if (result == JOptionPane.YES_OPTION) { + PrefStorage.unset("license"); + System.exit(0); + } + } + + public String license() { + String expires = "Error"; + if (PrefStorage.getSetting("licensetype").equals("demo")) { + Calendar c = Calendar.getInstance(); + c.setTime(new Date()); + try { + long expire = Long.parseLong(PrefStorage.getSetting("license")); + long days = (((expire - c.getTimeInMillis()) / (60 * 60 * 24)) - 999) / 1000; + if (days < 0) { + if (days == -1) { + expires = "Today"; + } else { + expires = abs(days) + " days ago"; + } + } else { + expires = "In " + days + " days"; + } + } catch (NumberFormatException e) { + } + } else { + try { + URL url = new URL(API_URL + "expire.php?email=" + PrefStorage.getSetting("license")); + try (InputStream is = url.openStream(); + BufferedReader br + = new BufferedReader(new InputStreamReader(is))) { + expires = br.readLine(); + } catch (IOException ex) { + } + } catch (Exception ex) { + } + } + String lic = "==License Information==\n" + + "License: " + PrefStorage.getSetting("license") + + "\nType: " + PrefStorage.getSetting("licensetype") + + "\nExpires: " + expires; + return lic; + } + + /** + * Make sure the graph window shows. + */ + private void showGraph() { + graphwin.setVisible(true); + graphwin.toFront(); + } + + public TextBox textbox() { + return new TextBox(); + } + + public WebBrowser browser() { + return new WebBrowser(); + } + /* + Constructor. + */ + + public Functions() { + Main.loadFrame(graphwin, false); + } + + public void setLang(String l) { + lang = l; + } + + /** + * This class finds permutations of an array. + * + * Credit to http://stackoverflow.com/a/14444037/2534036 + * + * License: CC-BY-SA 3.0 + * + * @param + */ + class Permutations implements Iterator { + + private final E[] arr; + private final int[] ind; + private boolean has_next; + + public E[] output;//next() returns this array, make it public + + Permutations(E[] arr) { + this.arr = arr.clone(); + ind = new int[arr.length]; + //convert an array of any elements into array of integers - first occurrence is used to enumerate + Map hm = new HashMap<>(); + for (int i = 0; i < arr.length; i++) { + Integer n = hm.get(arr[i]); + if (n == null) { + hm.put(arr[i], i); + n = i; + } + ind[i] = n; + } + Arrays.sort(ind);//start with ascending sequence of integers + + //output = new E[arr.length]; <-- cannot do in Java with generics, so use reflection + output = (E[]) Array.newInstance(arr.getClass().getComponentType(), arr.length); + has_next = true; + } + + @Override + public boolean hasNext() { + return has_next; + } + + /** + * Computes next permutations. Same array instance is returned every + * time! + * + * @return + */ + @Override + public E[] next() { + if (!has_next) { + throw new NoSuchElementException(); + } + + for (int i = 0; i < ind.length; i++) { + output[i] = arr[ind[i]]; + } + + //get next permutation + has_next = false; + for (int tail = ind.length - 1; tail > 0; tail--) { + if (ind[tail - 1] < ind[tail]) {//still increasing + + //find last element which does not exceed ind[tail-1] + int s = ind.length - 1; + while (ind[tail - 1] >= ind[s]) { + s--; + } + + swap(ind, tail - 1, s); + + //reverse order of elements in the tail + for (int i = tail, j = ind.length - 1; i < j; i++, j--) { + swap(ind, i, j); + } + has_next = true; + break; + } + + } + return output; + } + + private void swap(int[] arr, int i, int j) { + int t = arr[i]; + arr[i] = arr[j]; + arr[j] = t; + } + + @Override + public void remove() { + + } + } +} diff --git a/src/net/apocalypselabs/symat/Main.java b/src/net/apocalypselabs/symat/Main.java index 4f99181..baed86e 100644 --- a/src/net/apocalypselabs/symat/Main.java +++ b/src/net/apocalypselabs/symat/Main.java @@ -1,1142 +1,1155 @@ -/* - * CODE LICENSE ===================== - * Copyright (c) 2015, Apocalypse Laboratories - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors - * may be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * 4. You adhere to the Media License detailed below. If you do not, this license - * is automatically revoked and you must purge all copies of the software you - * possess, in source or binary form. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * MEDIA LICENSE ==================== - * All images and other graphical files (the "graphics") included with this - * software are copyright (c) 2015 Apocalypse Laboratories. You may not distribute - * the graphics or any program, source code repository, or other digital storage - * media containing them without written permission from Apocalypse Laboratories. - * This ban on distribution only applies to publicly available systems. - * A password-protected network file share, USB drive, or other storage scheme that - * cannot be easily accessed by the public is generally allowed. If in doubt, - * contact Apocalypse Laboratories. If Apocalypse Laboratories allows or denies - * you permission, that decision is considered final and binding. - */ -package net.apocalypselabs.symat; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Font; -import java.awt.FontFormatException; -import static java.awt.Frame.MAXIMIZED_BOTH; -import java.awt.Graphics; -import java.awt.Image; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; -import java.io.BufferedReader; -import java.io.File; -import java.io.FilenameFilter; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.net.URL; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Calendar; -import java.util.Date; -import java.util.GregorianCalendar; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import javafx.application.Platform; -import javafx.embed.swing.JFXPanel; -import javax.swing.ImageIcon; -import javax.swing.JFileChooser; -import javax.swing.JInternalFrame; -import javax.swing.JOptionPane; -import javax.swing.ListModel; -import javax.swing.SwingUtilities; -import javax.swing.UIManager; -import javax.swing.filechooser.FileFilter; -import javax.swing.filechooser.FileNameExtensionFilter; -import net.apocalypselabs.symat.plugin.LoadPlugin; -import org.pushingpixels.flamingo.api.ribbon.*; -import org.pushingpixels.flamingo.api.ribbon.resize.*; -import org.pushingpixels.flamingo.api.common.*; -import org.pushingpixels.flamingo.api.common.icon.*; - -/** - * This class is like the Force: A light theme, a dark theme, and it binds the - * app together. Also like duct tape, but that's not as cool. - * - * Contains a bunch of important variables and constants that are used all over. - * - * There is only one Main per app instance, the important things are static. - * - * @author Skylar Ittner - */ -public class Main extends JRibbonFrame { - - // TODO: Add more code comments and stuff in case anybody else reads this - /** - * Version name, as it should be displayed. - */ - public static final String VERSION_NAME = "2.0"; - - /** - * The word "SyMAT". - */ - public static final String SYMAT = "SyMAT"; - /** - * Program name, with version name - */ - public static final String APP_NAME = SYMAT + " " + VERSION_NAME; - /** - * Version number, for updates and //needs in scripts - */ - public static final double APP_CODE = 21; - /** - * Base URL for building API calls - */ - public static final String API_URL = "http://apis.symatapp.com/"; - /** - * Contains the filename argument passed to SyMAT, if any. - */ - public static String argfile = ""; - - /** - * Ubuntu font. Loaded from Ubuntu-R.ttf in the default package at runtime. - * May become default sans-serif if something bad happens. - */ - public static Font ubuntuRegular; - public static boolean skipPython = false; // Skip python init on start? - public static boolean skipEditor = false; // Skip editor init on start? - - private static boolean recentItemsMinimized = false; - - public static boolean updateAvailable = false; // Update available? - public static String updateString = ""; - - /** - * Application icon, for setting frame icons. Has different sizes. - */ - public static ArrayList symatlogo = new ArrayList<>(); - - /** - * The http server that handles opening other instances. - */ - public static SingleInstanceServer sisrv; - - public static Main maingui; - - public JRibbonBand pluginband; - - /** - * Creates the main app window and does some quick things that aren't - * threaded in SplashScreen. - */ - public Main() { - maingui = this; - // Set icon - setIconImages(symatlogo); - initComponents(); - loadRibbon(); - - // Center screen - setLocationRelativeTo(null); - - // Run things when app closed - addWindowListener(new WindowAdapter() { - @Override - public void windowClosing(WindowEvent we) { - int p = JOptionPane.showConfirmDialog(Main.mainPane, - "Are you sure you want to exit SyMAT?", - "Exit SyMAT", - JOptionPane.YES_NO_OPTION, - JOptionPane.QUESTION_MESSAGE); - if (p == JOptionPane.YES_OPTION) { - if (getExtendedState() == MAXIMIZED_BOTH) { - PrefStorage.saveSetting("framemaxed", "yes"); - } else { - PrefStorage.saveSetting("framemaxed", "no"); - } - System.exit(0); - } - } - }); - - // Open initial windows - boolean loaded = false; - if (!argfile.equals("")) { - if (argfile.endsWith(".sytt")) { - Tasks tt = new Tasks(new File(argfile)); - loadFrame(tt); - argfile = ""; - } else if (argfile.endsWith(".sypl")) { - loadFrame(new InstallPlugin(new File(argfile))); - } else { - Editor ed = new Editor(); - loadFrame(ed); - ed.openFileFromName(argfile); - argfile = ""; - } - loaded = true; - } - boolean licValid = false; - if (PrefStorage.getSetting("license").equals("") - || PrefStorage.getSetting("licensetype").equals("demo")) { - if (PrefStorage.getSetting("licensetype").equals("demo")) { - Calendar c = Calendar.getInstance(); - c.setTime(new Date()); - try { - long expire = Long.parseLong(PrefStorage.getSetting("license")); - if (expire > c.getTimeInMillis()) { - licValid = true; - } - } catch (NumberFormatException e) { - - } - } - } else { - try { - Debug.println("Checking license..."); - URL url = new URL(API_URL + "liccheck.php?email=" - + PrefStorage.getSetting("license") - + "&quick=1"); - String line; - try (InputStream is = url.openStream(); - BufferedReader br - = new BufferedReader(new InputStreamReader(is))) { - line = br.readLine(); - } - if (line.equals("ok")) { - licValid = true; - } - } catch (Exception ex) { - // Assume valid - licValid = true; - } - } - if (!licValid) { - licenseRestrict(true); - loadFrame(new License()); - loaded = true; - } - // Only load shell if nothing else is going on - if (argfile.equals("") && !loaded) { - loadFrame(new Interpreter()); - } - if (updateAvailable) { - loadFrame(new Update(updateString)); - } - loadRecentFiles(); - updateDisplay(); - setVisible(true); - if (PrefStorage.getSetting("framemaxed", "no").equals("yes")) { - java.awt.EventQueue.invokeLater(() -> { - setExtendedState(MAXIMIZED_BOTH); - }); - } - - if (!PrefStorage.getSetting("showrecent", "").equals("")) { - recentItemsPanel.setVisible(false); - } - - // Pi Day easter egg - GregorianCalendar piday = new GregorianCalendar(); - if ((piday.get(Calendar.MONTH) == 2) - && (piday.get(Calendar.DAY_OF_MONTH) == 14)) { - JOptionPane.showInternalMessageDialog(mainPane, - "Happy Pi Day from the SyMAT team!", - "3/14", - JOptionPane.PLAIN_MESSAGE); - } - } - - /** - * Load plugins from disk. - */ - public void loadPlugins() { - pluginband = new JRibbonBand("Plugins", null); - installpluginbtn.setActionRichTooltip(new RichTooltip("Install Plugin", - "Install a plugin from a file and view plugin info.")); - installpluginbtn.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent evt) { - loadFrame(new InstallPlugin()); - } - }); - pluginband.setResizePolicies((List) Arrays.asList( - new CoreRibbonResizePolicies.Mirror(pluginband.getControlPanel()))); - pluginband.addCommandButton(installpluginbtn, RibbonElementPriority.TOP); - String fsep = System.getProperty("file.separator"); - File dir = new File(System.getProperty("user.home") + fsep + ".symat" + fsep + "plugins"); - dir.mkdirs(); - File[] files = dir.listFiles(new FilenameFilter() { - @Override - public boolean accept(File dir, String name) { - return name.endsWith(".sypl"); - } - }); - - Map galleryVisibleButtonCounts = new HashMap<>(); - galleryVisibleButtonCounts.put(RibbonElementPriority.LOW, 1); - galleryVisibleButtonCounts.put(RibbonElementPriority.MEDIUM, 2); - galleryVisibleButtonCounts.put(RibbonElementPriority.TOP, 2); - List>> appGalleryButtons = new ArrayList<>(); - List appGalleryButtonsList = new ArrayList<>(); - if (files != null) { - for (File pl : files) { - LoadPlugin lp; - try { - lp = new LoadPlugin(pl); - appGalleryButtonsList.add(lp.getGalleryBtn()); - } catch (Exception ex) { - Debug.stacktrace(ex); - System.err.println("Error loading plugin " + pl.getName() + ": " + ex.getMessage()); - } - } - } - - appGalleryButtons.add(new StringValuePair<>("Plugins", - appGalleryButtonsList)); - pluginband.addRibbonGallery("Plugins", appGalleryButtons, - galleryVisibleButtonCounts, 5, 3, - RibbonElementPriority.TOP); - } - - /** - * Reload the Ribbon tabs and all sub-components. - */ - public void reloadRibbon() { - getRibbon().removeAllTasks(); - loadRibbon(); - } - - /** - * Load the ribbon in all its glory. - */ - private void loadRibbon() { - setApplicationIcon(ImageWrapperResizableIcon.getIcon( - Main.class.getResource("icon32.png"), - new Dimension(32, 32))); - JRibbon ribbon = getRibbon(); - JRibbonBand coreband = new JRibbonBand("Core", null); - JRibbonBand appsband = new JRibbonBand("Apps", null); - JRibbonBand webband = new JRibbonBand("Community", null); - JRibbonBand collabband = new JRibbonBand("Team", null); - //JRibbonBand getpluginband = new JRibbonBand("Install", null); - - try { - loadPlugins(); - } catch (Exception ex) { - JOptionPane.showMessageDialog(this, - "An error occurred while loading plugins: " - + ex.getMessage()); - } - - shellbtn.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent evt) { - loadFrame(new Interpreter()); - } - }); - editorbtn.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent evt) { - loadFrame(new Editor()); - } - }); - graphbtn.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent evt) { - loadFrame(new Graph()); - } - }); - notepadbtn.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent evt) { - loadFrame(new Notepad()); - } - }); - wikibtn.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent evt) { - loadFrame(new WebBrowser("SyMAT Wiki", - "http://wiki.symatapp.com", - WebBrowser.WIKI_LOGO)); - } - }); - forumbtn.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent evt) { - loadFrame(new WebBrowser("Community Forum", - "http://forum.symatapp.com/", - WebBrowser.FORUM_LOGO)); - } - }); - padsbtn.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent evt) { - loadFrame(new Pads()); - } - }); - tasksbtn.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent evt) { - loadFrame(new Tasks()); - } - }); - - shellbtn.setActionRichTooltip(new RichTooltip("Command Shell", - "Open a window for running interactive commands.")); - editorbtn.setActionRichTooltip(new RichTooltip("Code Editor", - "Write and run JavaScript and Python scripts.")); - graphbtn.setActionRichTooltip(new RichTooltip("Graph", - "Plot mathematical functions on a 2D graph.")); - notepadbtn.setActionRichTooltip(new RichTooltip("Notepad", - "Write quick notes on a virtual napkin.")); - wikibtn.setActionRichTooltip(new RichTooltip("SyMAT Wiki", - "View and edit online documentation and tutorials.")); - forumbtn.setActionRichTooltip(new RichTooltip("Support Forum", - "Discuss and share with the SyMAT community.")); - padsbtn.setActionRichTooltip(new RichTooltip("Code Pads", - "Collaborate over the Internet on projects.")); - tasksbtn.setActionRichTooltip(new RichTooltip("Task List", - "Manage tasks and to-do lists for projects.")); - - coreband.addCommandButton(shellbtn, RibbonElementPriority.TOP); - coreband.addCommandButton(editorbtn, RibbonElementPriority.TOP); - - appsband.addCommandButton(graphbtn, RibbonElementPriority.MEDIUM); - appsband.addCommandButton(notepadbtn, RibbonElementPriority.MEDIUM); - - webband.addCommandButton(wikibtn, RibbonElementPriority.LOW); - webband.addCommandButton(forumbtn, RibbonElementPriority.LOW); - - collabband.addCommandButton(padsbtn, RibbonElementPriority.MEDIUM); - collabband.addCommandButton(tasksbtn, RibbonElementPriority.MEDIUM); - - coreband.setResizePolicies((List) Arrays.asList( - new CoreRibbonResizePolicies.None(coreband.getControlPanel()), - new IconRibbonBandResizePolicy(coreband.getControlPanel()))); - appsband.setResizePolicies((List) Arrays.asList( - new CoreRibbonResizePolicies.None(appsband.getControlPanel()), - new IconRibbonBandResizePolicy(appsband.getControlPanel()))); - webband.setResizePolicies((List) Arrays.asList( - new CoreRibbonResizePolicies.None(webband.getControlPanel()), - new IconRibbonBandResizePolicy(webband.getControlPanel()))); - collabband.setResizePolicies((List) Arrays.asList( - new CoreRibbonResizePolicies.None(collabband.getControlPanel()), - new IconRibbonBandResizePolicy(collabband.getControlPanel()))); -// getpluginband.setResizePolicies((List) Arrays.asList( -// new CoreRibbonResizePolicies.None(appsband.getControlPanel()), -// new IconRibbonBandResizePolicy(pluginband.getControlPanel()))); -// pluginband.setResizePolicies((List) Arrays.asList( -// new CoreRibbonResizePolicies.None(appsband.getControlPanel()), -// new IconRibbonBandResizePolicy(pluginband.getControlPanel()))); - - RibbonTask hometask = new RibbonTask("Home", coreband, appsband); - RibbonTask webtask = new RibbonTask("Tools", webband, collabband); - RibbonTask plugintask = new RibbonTask("Plugins", pluginband); - - loadRibbonMenu(null); - - ribbon.addTask(hometask); - ribbon.addTask(webtask); - ribbon.addTask(plugintask); - } - - public static ResizableIcon getRibbonIcon(String name) { - return ImageWrapperResizableIcon.getIcon( - Main.class.getResource("images/" + name + ".png"), - new Dimension(100, 76)); - } - - public static ResizableIcon getTinyRibbonIcon(String name) { - int d = 32; - return ImageWrapperResizableIcon.getIcon( - Main.class.getResource("icons/" + name + ".png"), - new Dimension(d, d)); - } - - public static void licenseRestrict(boolean restricted) { - graphbtn.setEnabled(!restricted); - padsbtn.setEnabled(!restricted); - recentFileList.setEnabled(!restricted); - } - - /** - * (Re)load display settings. - */ - public static void updateDisplay() { - maingui.getRibbon().setBackground(Theme.tabColor()); - recentFileList.setForeground(Theme.textColor()); - recentFileList.setBackground(Theme.boxColor()); - recentItemsPanel.setVisible(PrefStorage.getSetting("showrecent", "") - .equals("")); - maingui.getRibbon().setMinimized(PrefStorage.getSetting( - "miniribbon", "").equals("yes")); - mainPane.paintImmediately(0, 0, - mainPane.getWidth(), mainPane.getHeight()); - } - - public static void loadRibbonMenu(RibbonApplicationMenuEntrySecondary[] recent) { - RibbonApplicationMenuEntryPrimary helpbtn - = new RibbonApplicationMenuEntryPrimary( - getRibbonIcon("help"), - "Manual", - new ActionListener() { - @Override - public void actionPerformed(ActionEvent evt) { - loadFrame(new Help()); - } - }, - JCommandButton.CommandButtonKind.ACTION_ONLY); - RibbonApplicationMenuEntryPrimary cascadebtn - = new RibbonApplicationMenuEntryPrimary( - getRibbonIcon("cascade"), - "Arrange all", - new ActionListener() { - @Override - public void actionPerformed(ActionEvent evt) { - cascade(); - } - }, - JCommandButton.CommandButtonKind.ACTION_ONLY); - RibbonApplicationMenuEntryPrimary exitbtn - = new RibbonApplicationMenuEntryPrimary( - getRibbonIcon("closeall"), - "Exit", - new ActionListener() { - @Override - public void actionPerformed(ActionEvent evt) { - maingui.dispatchEvent(new WindowEvent(maingui, - WindowEvent.WINDOW_CLOSING)); - } - }, - JCommandButton.CommandButtonKind.ACTION_ONLY); - RibbonApplicationMenuEntrySecondary newjsbtn - = new RibbonApplicationMenuEntrySecondary( - getTinyRibbonIcon("jsicon"), - "JavaScript", - new ActionListener() { - @Override - public void actionPerformed(ActionEvent evt) { - loadFrame(new Editor()); - } - }, - JCommandButton.CommandButtonKind.ACTION_ONLY); - RibbonApplicationMenuEntrySecondary newpybtn - = new RibbonApplicationMenuEntrySecondary( - getTinyRibbonIcon("pyicon"), - "Python", - new ActionListener() { - @Override - public void actionPerformed(ActionEvent evt) { - loadFrame(new Editor(true)); - } - }, - JCommandButton.CommandButtonKind.ACTION_ONLY); - RibbonApplicationMenuEntrySecondary newtaskbtn - = new RibbonApplicationMenuEntrySecondary( - getTinyRibbonIcon("taskicon"), - "Task List", - new ActionListener() { - @Override - public void actionPerformed(ActionEvent evt) { - loadFrame(new Tasks()); - } - }, - JCommandButton.CommandButtonKind.ACTION_ONLY); - RibbonApplicationMenuEntryPrimary newbtn - = new RibbonApplicationMenuEntryPrimary( - getRibbonIcon("newfile"), - "New", - null, - JCommandButton.CommandButtonKind.POPUP_ONLY); - openbtn = new RibbonApplicationMenuEntryPrimary( - getRibbonIcon("openfile"), - "Open", - new ActionListener() { - @Override - public void actionPerformed(ActionEvent evt) { - JFileChooser fc = new JFileChooser(); - FileFilter script - = new FileNameExtensionFilter("Script" - + "(syjs, sypy, js, py)", - "syjs", "sypy", "js", "py"); - FileFilter all - = new FileNameExtensionFilter("SyMAT File" - + "(syjs, sypy, js, py, sytt)", - "syjs", "sypy", "js", "py", "sytt"); - FileFilter tasklist - = new FileNameExtensionFilter("Task List (sytt)", - "sytt"); - fc.setFileFilter(all); - fc.addChoosableFileFilter(script); - fc.addChoosableFileFilter(tasklist); - int result = fc.showOpenDialog(maingui); - if (result == JFileChooser.APPROVE_OPTION) { - File f = fc.getSelectedFile(); - if (f.getName().endsWith(".sytt")) { - loadFrame(new Tasks(f)); - } else { - Editor ed = new Editor(); - ed.openFileFromName(f.getAbsolutePath()); - loadFrame(ed); - } - } - } - }, - JCommandButton.CommandButtonKind.ACTION_AND_POPUP_MAIN_ACTION); - - if (recent == null) { - RibbonApplicationMenuEntrySecondary blanksubbtn - = new RibbonApplicationMenuEntrySecondary( - null, "No recent files", null, - JCommandButton.CommandButtonKind.ACTION_ONLY); - blanksubbtn.setEnabled(false); - openbtn.addSecondaryMenuGroup("Recent Files", blanksubbtn); - } else { - openbtn.addSecondaryMenuGroup("Recent Files", recent); - } - newbtn.addSecondaryMenuGroup("Code File", newjsbtn, newpybtn); - newbtn.addSecondaryMenuGroup("Other", newtaskbtn); - - RibbonApplicationMenuEntryFooter displaybtn - = new RibbonApplicationMenuEntryFooter( - getTinyRibbonIcon("settings"), - "Settings", - new ActionListener() { - @Override - public void actionPerformed(ActionEvent evt) { - loadFrame(new Settings()); - } - }); - - RibbonApplicationMenuEntryPrimary blankbtn - = new RibbonApplicationMenuEntryPrimary( - null, "", null, - JCommandButton.CommandButtonKind.ACTION_ONLY); - blankbtn.setEnabled(false); - - RibbonApplicationMenu menu = new RibbonApplicationMenu(); - menu.addMenuEntry(newbtn); - menu.addMenuEntry(openbtn); - menu.addMenuSeparator(); - menu.addMenuEntry(helpbtn); - menu.addMenuEntry(cascadebtn); - menu.addMenuSeparator(); - menu.addMenuEntry(exitbtn); - menu.addFooterEntry(displaybtn); - - menu.addMenuEntry(blankbtn); - menu.addMenuEntry(blankbtn); - menu.addMenuEntry(blankbtn); - menu.addMenuEntry(blankbtn); - - maingui.getRibbon().setApplicationMenu(menu); - maingui.getRibbon().setApplicationMenuRichTooltip( - new RichTooltip("SyMAT Menu", - "Create files, open documents, " - + "get help, and change settings") - ); - } - - /** - * (Re)load recent file lists from storage. - */ - public static void loadRecentFiles() { - String files = PrefStorage.getSetting("recentfiles"); - if (files.equals("")) { - loadRibbonMenu(null); - recentFileList.setListData(new String[0]); - return; - } - String[] fileList = files.split("\n"); - int neededLength = 0; - for (String file : fileList) { - if ((new File(file)).isFile()) { - neededLength++; - } - } - if (neededLength > 10) { - neededLength = 10; - } - KeyValListItem[] items = new KeyValListItem[neededLength]; - int i = 0; - RibbonApplicationMenuEntrySecondary[] recentmenu - = new RibbonApplicationMenuEntrySecondary[fileList.length]; - for (String f : fileList) { - File file = new File(f); - if (file.isFile() && i < neededLength) { - items[i] = new KeyValListItem(file.getName(), file.getPath()); - recentmenu[i] = (new RibbonApplicationMenuEntrySecondary( - null, - file.getName(), - new ActionListener() { - final String path = file.getPath(); - - @Override - public void actionPerformed(ActionEvent evt) { - Editor edit = new Editor(); - edit.openFileFromName(path); - loadFrame(edit); - } - }, - JCommandButton.CommandButtonKind.ACTION_ONLY)); - i++; - } - } - - loadRibbonMenu(recentmenu); - recentFileList.setListData(items); - - // Re-save list to remove bad entries - String list = ""; - for (KeyValListItem item : items) { - list += item.getValue() + "\n"; - } - PrefStorage.saveSetting("recentfiles", list); - } - - /** - * Add a file to the recent files lists. - * - * @param file The file path. - */ - public static void addRecentFile(String file) { - file = (new File(file)).getAbsolutePath(); - String files = PrefStorage.getSetting("recentfiles"); - String[] fileList = files.split("\n"); - for (int i = 0; i < fileList.length; i++) { - if (fileList[i].trim().equals(file)) { - fileList[i] = ""; - } - } - files = file + "\n"; - for (String f : fileList) { - if (!f.trim().equals("")) { - files += f + "\n"; - } - } - PrefStorage.saveSetting("recentfiles", files); - PrefStorage.save(); - loadRecentFiles(); - } - - /** - * This method is called from within the constructor to initialize the form. - * WARNING: Do NOT modify this code. The content of this method is always - * regenerated by the Form Editor. - */ - @SuppressWarnings("unchecked") - // //GEN-BEGIN:initComponents - private void initComponents() { - - jMenuItem1 = new javax.swing.JMenuItem(); - mainPane = mainPane = new javax.swing.JDesktopPane() { - @Override - protected void paintComponent(Graphics g) { - super.paintComponent(g); - if (PrefStorage.getSetting("theme").equals("dark")) { - g.setColor(Color.DARK_GRAY); - } else { - g.setColor(Color.LIGHT_GRAY); - } - g.fillRect(0, 0, getWidth(), getHeight()); - } - } - ; - jLabel2 = new javax.swing.JLabel(); - recentItemsPanel = new javax.swing.JPanel(); - jScrollPane1 = new javax.swing.JScrollPane(); - recentFileList = new javax.swing.JList(); - recentFileBtn = new javax.swing.JButton(); - recentItemsTitle = new javax.swing.JLabel(); - appPanel = new javax.swing.JPanel(); - - jMenuItem1.setText("jMenuItem1"); - - setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE); - setTitle("SyMAT"); - setMinimumSize(new java.awt.Dimension(640, 540)); - addComponentListener(new java.awt.event.ComponentAdapter() { - public void componentShown(java.awt.event.ComponentEvent evt) { - formComponentShown(evt); - } - }); - - mainPane.setBackground(new java.awt.Color(204, 204, 204)); - mainPane.setAutoscrolls(true); - mainPane.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR)); - mainPane.setOpaque(false); - - jLabel2.setFont(Main.ubuntuRegular.deriveFont(48.0F)); - jLabel2.setForeground(new java.awt.Color(153, 153, 153)); - jLabel2.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); - jLabel2.setText("SyMAT"); - jLabel2.setVerticalAlignment(javax.swing.SwingConstants.BOTTOM); - - recentItemsPanel.setBorder(javax.swing.BorderFactory.createEtchedBorder()); - recentItemsPanel.setForeground(new java.awt.Color(153, 153, 153)); - recentItemsPanel.setMaximumSize(new java.awt.Dimension(160, 273)); - recentItemsPanel.setOpaque(false); - - jScrollPane1.setMinimumSize(new java.awt.Dimension(23, 206)); - jScrollPane1.setName(""); // NOI18N - - recentFileList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); - recentFileList.addMouseListener(new java.awt.event.MouseAdapter() { - public void mouseClicked(java.awt.event.MouseEvent evt) { - recentFileListMouseClicked(evt); - } - }); - recentFileList.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() { - public void mouseMoved(java.awt.event.MouseEvent evt) { - recentFileListMouseMoved(evt); - } - }); - jScrollPane1.setViewportView(recentFileList); - - recentFileBtn.setIcon(new javax.swing.ImageIcon(getClass().getResource("/net/apocalypselabs/symat/icons/openfile.png"))); // NOI18N - recentFileBtn.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - recentFileBtnActionPerformed(evt); - } - }); - - recentItemsTitle.setFont(new java.awt.Font("Tahoma", 1, 12)); // NOI18N - recentItemsTitle.setForeground(new java.awt.Color(102, 102, 102)); - recentItemsTitle.setText(" Recent Files"); - recentItemsTitle.setOpaque(true); - recentItemsTitle.addMouseListener(new java.awt.event.MouseAdapter() { - public void mouseClicked(java.awt.event.MouseEvent evt) { - recentItemsTitleMouseClicked(evt); - } - }); - - javax.swing.GroupLayout recentItemsPanelLayout = new javax.swing.GroupLayout(recentItemsPanel); - recentItemsPanel.setLayout(recentItemsPanelLayout); - recentItemsPanelLayout.setHorizontalGroup( - recentItemsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(recentItemsPanelLayout.createSequentialGroup() - .addGroup(recentItemsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(recentItemsPanelLayout.createSequentialGroup() - .addGap(97, 97, 97) - .addComponent(recentFileBtn)) - .addGroup(recentItemsPanelLayout.createSequentialGroup() - .addContainerGap() - .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 136, javax.swing.GroupLayout.PREFERRED_SIZE))) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addComponent(recentItemsTitle, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - ); - recentItemsPanelLayout.setVerticalGroup( - recentItemsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(recentItemsPanelLayout.createSequentialGroup() - .addComponent(recentItemsTitle) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 357, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(recentFileBtn) - .addContainerGap()) - ); - - appPanel.setOpaque(false); - appPanel.setLayout(new java.awt.GridBagLayout()); - - javax.swing.GroupLayout mainPaneLayout = new javax.swing.GroupLayout(mainPane); - mainPane.setLayout(mainPaneLayout); - mainPaneLayout.setHorizontalGroup( - mainPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, mainPaneLayout.createSequentialGroup() - .addContainerGap() - .addComponent(appPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(mainPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) - .addComponent(recentItemsPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(jLabel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addContainerGap()) - ); - mainPaneLayout.setVerticalGroup( - mainPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(mainPaneLayout.createSequentialGroup() - .addContainerGap() - .addGroup(mainPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(appPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(mainPaneLayout.createSequentialGroup() - .addComponent(recentItemsPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 84, Short.MAX_VALUE) - .addComponent(jLabel2))) - .addContainerGap()) - ); - mainPane.setLayer(jLabel2, javax.swing.JLayeredPane.DEFAULT_LAYER); - mainPane.setLayer(recentItemsPanel, javax.swing.JLayeredPane.DEFAULT_LAYER); - mainPane.setLayer(appPanel, javax.swing.JLayeredPane.DEFAULT_LAYER); - - getContentPane().add(mainPane, java.awt.BorderLayout.CENTER); - - pack(); - }// //GEN-END:initComponents - - private void formComponentShown(java.awt.event.ComponentEvent evt) {//GEN-FIRST:event_formComponentShown - setLocationRelativeTo(null); - }//GEN-LAST:event_formComponentShown - - private void recentFileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_recentFileBtnActionPerformed - if (recentFileList.getSelectedValue() == null) { - return; - } - KeyValListItem file = (KeyValListItem) recentFileList.getSelectedValue(); - if (file.isEmpty()) { - return; - } - Editor edit = new Editor(); - Debug.println(file.getValue()); - edit.openFileFromName(file.getValue()); - loadFrame(edit); - }//GEN-LAST:event_recentFileBtnActionPerformed - - private void recentFileListMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_recentFileListMouseClicked - if (evt.getClickCount() == 2) { - recentFileBtnActionPerformed(null); - } - }//GEN-LAST:event_recentFileListMouseClicked - - private void recentFileListMouseMoved(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_recentFileListMouseMoved - try { - ListModel m = recentFileList.getModel(); - int index = recentFileList.locationToIndex(evt.getPoint()); - if (index > -1) { - recentFileList.setToolTipText( - ((KeyValListItem) m.getElementAt(index)).getValue()); - } - } catch (Exception ex) { - // This feature is optional. Just skip it if it's broken. - recentFileList.setToolTipText(""); - } - }//GEN-LAST:event_recentFileListMouseMoved - - private void recentItemsTitleMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_recentItemsTitleMouseClicked - - }//GEN-LAST:event_recentItemsTitleMouseClicked - - /** - * Adds the given JInternalFrame to the mainPane. Automatically does layout - * and sets visible (if show==true). - * - * @param frame The frame - * @param show Should the frame be visible? - */ - public static void loadFrame(JInternalFrame frame, boolean show) { - int w = frame.getWidth(); - int h = frame.getHeight(); - int pw = mainPane.getWidth(); - int ph = mainPane.getHeight(); - if (frame.isResizable()) { - if (h > ph) { - h = ph; - } - if (w > pw) { - w = pw; - } - frame.setSize(w, h); - } - mainPane.add(frame); - frame.setLocation( - (pw / 2) - (w / 2), - (ph / 2) - (h / 2)); - if (frame.getLocation().y < 0) { - frame.setLocation(frame.getLocation().x, 0); - } - if (show) { - frame.setVisible(true); - } - } - - /** - * Adds the given JInternalFrame to the mainPane. Automatically does layout - * and sets visible. - * - * @param frame The frame - */ - public static void loadFrame(JInternalFrame frame) { - loadFrame(frame, true); - } - - /** - * Cascade all the frames in a stack. Somehow reverses the order each time - * around, I have no idea why but it's a "feature" now! - */ - public static void cascade() { - JInternalFrame[] frames = mainPane.getAllFrames(); - int x = 12; - int y = 24; - Debug.println("Cascading " + frames.length + " frames..."); - for (int i = 0; i < frames.length; i++) { - if (frames[i].isVisible()) { - Debug.println("Frame: " - + frames[i].getTitle() - + ", Times: " + i - + ", Xpos: " + x * i - + ", Ypos: " + y * i); - frames[i].setBounds(x * i, - y * i, - frames[i].getWidth(), - frames[i].getHeight()); - frames[i].toFront(); - } - } - } - - /** - * @param args the command line arguments - */ - public static void main(String args[]) { - /* Set the Nimbus look and feel */ - // - /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel. - * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html - */ - - try { - for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) { - if ("Nimbus".equals(info.getName())) { - UIManager.setLookAndFeel(info.getClassName()); - break; - } - } - } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | javax.swing.UnsupportedLookAndFeelException e) { - java.util.logging.Logger.getLogger(Main.class.getName()).log(java.util.logging.Level.SEVERE, null, e); - } - // - // - // - // - - try { - // Ubuntu font for prettifying - ubuntuRegular = Font.createFont(Font.TRUETYPE_FONT, Main.class. - getResourceAsStream("/Ubuntu-R.ttf")); - } catch (FontFormatException | IOException ex) { - ubuntuRegular = Font.getFont(Font.SANS_SERIF); - System.err.println("Error loading fonts: " + ex.getMessage()); - } catch (Exception ex) { - ubuntuRegular = Font.getFont(Font.SANS_SERIF); - System.err.println("Error loading fonts: " + ex.getMessage()); - } - - // Set icon - String[] sizes = {"16", "24", "32", "48", "64", "96", "128", "256", "512"}; - for (String s : sizes) { - symatlogo.add(new ImageIcon( - Main.class.getResource(s + "x" + s + ".png")).getImage()); - } - - // Command line args - for (String arg : args) { - switch (arg) { - case "skippython": - skipPython = true; - break; - case "skipeditor": - skipEditor = true; - break; - case "quickstart": - skipPython = true; - skipEditor = true; - break; - case "licensereset": - PrefStorage.saveSetting("license", ""); - break; - default: - argfile = arg; - break; - } - } - - SingleInstanceClient sicli = new SingleInstanceClient(argfile); - - try { - new SingleInstanceServer().start(); - } catch (IOException ex) { - Debug.printerr("Cannot start instance listener:\n\n"); - Debug.stacktrace(ex); - } - - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - new JFXPanel(); // this will prepare JavaFX toolkit and environment - Platform.runLater(new Runnable() { - @Override - public void run() { - Platform.setImplicitExit(false); - } - }); - } - }); - - - /* Create and display the form */ - java.awt.EventQueue.invokeLater(() -> { - new SplashScreen().setVisible(true); - }); - } - - public static JCommandButton shellbtn - = new JCommandButton("Shell", getRibbonIcon("shell")); - public static JCommandButton editorbtn - = new JCommandButton("Editor", getRibbonIcon("editor")); - public static JCommandButton graphbtn - = new JCommandButton("Graph", getRibbonIcon("graph")); - public static JCommandButton notepadbtn - = new JCommandButton("Notepad", getRibbonIcon("notepad")); - public static JCommandButton wikibtn - = new JCommandButton("Wiki", getRibbonIcon("wiki")); - public static JCommandButton forumbtn - = new JCommandButton("Forum", getRibbonIcon("forum")); - public static JCommandButton padsbtn - = new JCommandButton("Pads", getRibbonIcon("pads")); - public static JCommandButton tasksbtn - = new JCommandButton("Tasks", getRibbonIcon("tasks")); - public static JCommandButton installpluginbtn - = new JCommandButton("Install", getRibbonIcon("installplugin")); - public static RibbonApplicationMenuEntryPrimary openbtn; - - // Variables declaration - do not modify//GEN-BEGIN:variables - public static javax.swing.JPanel appPanel; - public static javax.swing.JLabel jLabel2; - public static javax.swing.JMenuItem jMenuItem1; - public static javax.swing.JScrollPane jScrollPane1; - public static javax.swing.JDesktopPane mainPane; - public static javax.swing.JButton recentFileBtn; - public static javax.swing.JList recentFileList; - public static javax.swing.JPanel recentItemsPanel; - public static javax.swing.JLabel recentItemsTitle; - // End of variables declaration//GEN-END:variables -} +/* + * CODE LICENSE ===================== + * Copyright (c) 2015, Apocalypse Laboratories + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * 4. You adhere to the Media License detailed below. If you do not, this license + * is automatically revoked and you must purge all copies of the software you + * possess, in source or binary form. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * MEDIA LICENSE ==================== + * All images and other graphical files (the "graphics") included with this + * software are copyright (c) 2015 Apocalypse Laboratories. You may not distribute + * the graphics or any program, source code repository, or other digital storage + * media containing them without written permission from Apocalypse Laboratories. + * This ban on distribution only applies to publicly available systems. + * A password-protected network file share, USB drive, or other storage scheme that + * cannot be easily accessed by the public is generally allowed. If in doubt, + * contact Apocalypse Laboratories. If Apocalypse Laboratories allows or denies + * you permission, that decision is considered final and binding. + */ +package net.apocalypselabs.symat; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontFormatException; +import static java.awt.Frame.MAXIMIZED_BOTH; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.BufferedReader; +import java.io.File; +import java.io.FilenameFilter; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javafx.application.Platform; +import javafx.embed.swing.JFXPanel; +import javax.swing.ImageIcon; +import javax.swing.JFileChooser; +import javax.swing.JInternalFrame; +import javax.swing.JOptionPane; +import javax.swing.ListModel; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.filechooser.FileFilter; +import javax.swing.filechooser.FileNameExtensionFilter; +import net.apocalypselabs.symat.plugin.LoadPlugin; +import org.pushingpixels.flamingo.api.ribbon.*; +import org.pushingpixels.flamingo.api.ribbon.resize.*; +import org.pushingpixels.flamingo.api.common.*; +import org.pushingpixels.flamingo.api.common.icon.*; + +/** + * This class is like the Force: A light theme, a dark theme, and it binds the + * app together. Also like duct tape, but that's not as cool. + * + * Contains a bunch of important variables and constants that are used all over. + * + * There is only one Main per app instance, the important things are static. + * + * @author Skylar Ittner + */ +public class Main extends JRibbonFrame { + + // TODO: Add more code comments and stuff in case anybody else reads this + /** + * Version name, as it should be displayed. + */ + public static final String VERSION_NAME = "2.0"; + + /** + * The word "SyMAT". + */ + public static final String SYMAT = "SyMAT"; + /** + * Program name, with version name + */ + public static final String APP_NAME = SYMAT + " " + VERSION_NAME; + /** + * Version number, for updates and //needs in scripts + */ + public static final double APP_CODE = 21; + /** + * Base URL for building API calls + */ + public static final String API_URL = "http://apis.symatapp.com/"; + /** + * Contains the filename argument passed to SyMAT, if any. + */ + public static String argfile = ""; + + /** + * Ubuntu font. Loaded from Ubuntu-R.ttf in the default package at runtime. + * May become default sans-serif if something bad happens. + */ + public static Font ubuntuRegular; + public static boolean skipPython = false; // Skip python init on start? + public static boolean skipEditor = false; // Skip editor init on start? + + private static boolean recentItemsMinimized = false; + + public static boolean updateAvailable = false; // Update available? + public static String updateString = ""; + + /** + * Application icon, for setting frame icons. Has different sizes. + */ + public static ArrayList symatlogo = new ArrayList<>(); + + /** + * The http server that handles opening other instances. + */ + public static SingleInstanceServer sisrv; + + public static Main maingui; + + public JRibbonBand pluginband; + + /** + * Creates the main app window and does some quick things that aren't + * threaded in SplashScreen. + */ + public Main() { + maingui = this; + // Set icon + setIconImages(symatlogo); + initComponents(); + loadRibbon(); + + // Center screen + setLocationRelativeTo(null); + + // Run things when app closed + addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent we) { + int p = JOptionPane.showConfirmDialog(Main.mainPane, + "Are you sure you want to exit SyMAT?", + "Exit SyMAT", + JOptionPane.YES_NO_OPTION, + JOptionPane.QUESTION_MESSAGE); + if (p == JOptionPane.YES_OPTION) { + if (getExtendedState() == MAXIMIZED_BOTH) { + PrefStorage.saveSetting("framemaxed", "yes"); + } else { + PrefStorage.saveSetting("framemaxed", "no"); + } + System.exit(0); + } + } + }); + + // Open initial windows + boolean loaded = false; + if (!argfile.equals("")) { + if (argfile.endsWith(".sytt")) { + Tasks tt = new Tasks(new File(argfile)); + loadFrame(tt); + argfile = ""; + } else if (argfile.endsWith(".sypl")) { + loadFrame(new InstallPlugin(new File(argfile))); + } else { + Editor ed = new Editor(); + loadFrame(ed); + ed.openFileFromName(argfile); + argfile = ""; + } + loaded = true; + } + boolean licValid = false; + if (PrefStorage.getSetting("license").equals("") + || PrefStorage.getSetting("licensetype").equals("demo")) { + if (PrefStorage.getSetting("licensetype").equals("demo")) { + Calendar c = Calendar.getInstance(); + c.setTime(new Date()); + try { + long expire = Long.parseLong(PrefStorage.getSetting("license")); + if (expire > c.getTimeInMillis()) { + licValid = true; + } + } catch (NumberFormatException e) { + + } + } + } else { + try { + Debug.println("Checking license..."); + URL url = new URL(API_URL + "liccheck.php?email=" + + PrefStorage.getSetting("license") + + "&quick=1"); + String line; + try (InputStream is = url.openStream(); + BufferedReader br + = new BufferedReader(new InputStreamReader(is))) { + line = br.readLine(); + } + if (line.equals("ok")) { + licValid = true; + } + } catch (Exception ex) { + // Assume valid + licValid = true; + } + } + if (!licValid) { + licenseRestrict(true); + loadFrame(new License()); + loaded = true; + } + // Only load shell if nothing else is going on + if (argfile.equals("") && !loaded) { + loadFrame(new Interpreter()); + } + if (updateAvailable) { + loadFrame(new Update(updateString)); + } + loadRecentFiles(); + updateDisplay(); + setVisible(true); + if (PrefStorage.getSetting("framemaxed", "no").equals("yes")) { + java.awt.EventQueue.invokeLater(() -> { + setExtendedState(MAXIMIZED_BOTH); + }); + } + + if (!PrefStorage.getSetting("showrecent", "").equals("")) { + recentItemsPanel.setVisible(false); + } + + // Pi Day easter egg + GregorianCalendar piday = new GregorianCalendar(); + if ((piday.get(Calendar.MONTH) == 2) + && (piday.get(Calendar.DAY_OF_MONTH) == 14)) { + JOptionPane.showInternalMessageDialog(mainPane, + "Happy Pi Day from the SyMAT team!", + "3/14", + JOptionPane.PLAIN_MESSAGE); + } + } + + /** + * Load plugins from disk. + */ + public void loadPlugins() { + pluginband = new JRibbonBand("Plugins", null); + installpluginbtn.setActionRichTooltip(new RichTooltip("Install Plugin", + "Install a plugin from a file and view plugin info.")); + installpluginbtn.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent evt) { + loadFrame(new InstallPlugin()); + } + }); + pluginband.setResizePolicies((List) Arrays.asList( + new CoreRibbonResizePolicies.Mirror(pluginband.getControlPanel()))); + pluginband.addCommandButton(installpluginbtn, RibbonElementPriority.TOP); + String fsep = System.getProperty("file.separator"); + File dir = new File(System.getProperty("user.home") + fsep + ".symat" + fsep + "plugins"); + dir.mkdirs(); + File[] files = dir.listFiles(new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + return name.endsWith(".sypl"); + } + }); + + Map galleryVisibleButtonCounts = new HashMap<>(); + galleryVisibleButtonCounts.put(RibbonElementPriority.LOW, 4); + galleryVisibleButtonCounts.put(RibbonElementPriority.MEDIUM, 4); + galleryVisibleButtonCounts.put(RibbonElementPriority.TOP, 4); + List>> appGalleryButtons = new ArrayList<>(); + List appGalleryButtonsList = new ArrayList<>(); + if (files != null) { + for (File pl : files) { + LoadPlugin lp; + try { + lp = new LoadPlugin(pl); + appGalleryButtonsList.add(lp.getGalleryBtn()); + } catch (Exception ex) { + Debug.stacktrace(ex); + System.err.println("Error loading plugin " + pl.getName() + ": " + ex.getMessage()); + } + } + } + + appGalleryButtons.add(new StringValuePair<>("Plugins", + appGalleryButtonsList)); + pluginband.addRibbonGallery("Plugins", appGalleryButtons, + galleryVisibleButtonCounts, 4, 3, + RibbonElementPriority.TOP); + } + + /** + * Reload the Ribbon tabs and all sub-components. + */ + public void reloadRibbon() { + getRibbon().removeAllTasks(); + loadRibbon(); + } + + /** + * Load the ribbon in all its glory. + */ + private void loadRibbon() { + ResizableIcon appico = ImageWrapperResizableIcon.getIcon( + Main.class.getResource("icon32.png"), + new Dimension(32, 32)); + setApplicationIcon(appico); + int tries = 0; // no infinite loops for us! + while (tries < 20) { + try { + Thread.sleep(10); + if (getApplicationIcon().equals(appico)) { + break; + } + setApplicationIcon(appico); + } catch (Exception ex) { + } + tries++; + } + JRibbon ribbon = getRibbon(); + JRibbonBand coreband = new JRibbonBand("Core", null); + JRibbonBand appsband = new JRibbonBand("Apps", null); + JRibbonBand webband = new JRibbonBand("Community", null); + JRibbonBand collabband = new JRibbonBand("Team", null); + //JRibbonBand getpluginband = new JRibbonBand("Install", null); + + try { + loadPlugins(); + } catch (Exception ex) { + JOptionPane.showMessageDialog(this, + "An error occurred while loading plugins: " + + ex.getMessage()); + } + + shellbtn.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent evt) { + loadFrame(new Interpreter()); + } + }); + editorbtn.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent evt) { + loadFrame(new Editor()); + } + }); + graphbtn.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent evt) { + loadFrame(new Graph()); + } + }); + notepadbtn.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent evt) { + loadFrame(new Notepad()); + } + }); + wikibtn.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent evt) { + loadFrame(new WebBrowser("SyMAT Wiki", + "http://wiki.symatapp.com", + WebBrowser.WIKI_LOGO)); + } + }); + forumbtn.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent evt) { + loadFrame(new WebBrowser("Community Forum", + "http://forum.symatapp.com/", + WebBrowser.FORUM_LOGO)); + } + }); + padsbtn.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent evt) { + loadFrame(new Pads()); + } + }); + tasksbtn.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent evt) { + loadFrame(new Tasks()); + } + }); + + shellbtn.setActionRichTooltip(new RichTooltip("Command Shell", + "Open a window for running interactive commands.")); + editorbtn.setActionRichTooltip(new RichTooltip("Code Editor", + "Write and run JavaScript and Python scripts.")); + graphbtn.setActionRichTooltip(new RichTooltip("Graph", + "Plot mathematical functions on a 2D graph.")); + notepadbtn.setActionRichTooltip(new RichTooltip("Notepad", + "Write quick notes on a virtual napkin.")); + wikibtn.setActionRichTooltip(new RichTooltip("SyMAT Wiki", + "View and edit online documentation and tutorials.")); + forumbtn.setActionRichTooltip(new RichTooltip("Support Forum", + "Discuss and share with the SyMAT community.")); + padsbtn.setActionRichTooltip(new RichTooltip("Code Pads", + "Collaborate over the Internet on projects.")); + tasksbtn.setActionRichTooltip(new RichTooltip("Task List", + "Manage tasks and to-do lists for projects.")); + + coreband.addCommandButton(shellbtn, RibbonElementPriority.TOP); + coreband.addCommandButton(editorbtn, RibbonElementPriority.TOP); + + appsband.addCommandButton(graphbtn, RibbonElementPriority.MEDIUM); + appsband.addCommandButton(notepadbtn, RibbonElementPriority.MEDIUM); + + webband.addCommandButton(wikibtn, RibbonElementPriority.LOW); + webband.addCommandButton(forumbtn, RibbonElementPriority.LOW); + + collabband.addCommandButton(padsbtn, RibbonElementPriority.MEDIUM); + collabband.addCommandButton(tasksbtn, RibbonElementPriority.MEDIUM); + + coreband.setResizePolicies((List) Arrays.asList( + new CoreRibbonResizePolicies.None(coreband.getControlPanel()), + new IconRibbonBandResizePolicy(coreband.getControlPanel()))); + appsband.setResizePolicies((List) Arrays.asList( + new CoreRibbonResizePolicies.None(appsband.getControlPanel()), + new IconRibbonBandResizePolicy(appsband.getControlPanel()))); + webband.setResizePolicies((List) Arrays.asList( + new CoreRibbonResizePolicies.None(webband.getControlPanel()), + new IconRibbonBandResizePolicy(webband.getControlPanel()))); + collabband.setResizePolicies((List) Arrays.asList( + new CoreRibbonResizePolicies.None(collabband.getControlPanel()), + new IconRibbonBandResizePolicy(collabband.getControlPanel()))); +// getpluginband.setResizePolicies((List) Arrays.asList( +// new CoreRibbonResizePolicies.None(appsband.getControlPanel()), +// new IconRibbonBandResizePolicy(pluginband.getControlPanel()))); +// pluginband.setResizePolicies((List) Arrays.asList( +// new CoreRibbonResizePolicies.None(appsband.getControlPanel()), +// new IconRibbonBandResizePolicy(pluginband.getControlPanel()))); + + RibbonTask hometask = new RibbonTask("Home", coreband, appsband); + RibbonTask webtask = new RibbonTask("Tools", webband, collabband); + RibbonTask plugintask = new RibbonTask("Plugins", pluginband); + + loadRibbonMenu(null); + + ribbon.addTask(hometask); + ribbon.addTask(webtask); + ribbon.addTask(plugintask); + } + + public static ResizableIcon getRibbonIcon(String name) { + return ImageWrapperResizableIcon.getIcon( + Main.class.getResource("images/" + name + ".png"), + new Dimension(100, 76)); + } + + public static ResizableIcon getTinyRibbonIcon(String name) { + int d = 32; + return ImageWrapperResizableIcon.getIcon( + Main.class.getResource("icons/" + name + ".png"), + new Dimension(d, d)); + } + + public static void licenseRestrict(boolean restricted) { + graphbtn.setEnabled(!restricted); + padsbtn.setEnabled(!restricted); + recentFileList.setEnabled(!restricted); + } + + /** + * (Re)load display settings. + */ + public static void updateDisplay() { + maingui.getRibbon().setBackground(Theme.tabColor()); + recentFileList.setForeground(Theme.textColor()); + recentFileList.setBackground(Theme.boxColor()); + recentItemsPanel.setVisible(PrefStorage.getSetting("showrecent", "") + .equals("")); + maingui.getRibbon().setMinimized(PrefStorage.getSetting( + "miniribbon", "").equals("yes")); + mainPane.paintImmediately(0, 0, + mainPane.getWidth(), mainPane.getHeight()); + } + + public static void loadRibbonMenu(RibbonApplicationMenuEntrySecondary[] recent) { + RibbonApplicationMenuEntryPrimary helpbtn + = new RibbonApplicationMenuEntryPrimary( + getRibbonIcon("help"), + "Manual", + new ActionListener() { + @Override + public void actionPerformed(ActionEvent evt) { + loadFrame(new Help()); + } + }, + JCommandButton.CommandButtonKind.ACTION_ONLY); + RibbonApplicationMenuEntryPrimary cascadebtn + = new RibbonApplicationMenuEntryPrimary( + getRibbonIcon("cascade"), + "Arrange all", + new ActionListener() { + @Override + public void actionPerformed(ActionEvent evt) { + cascade(); + } + }, + JCommandButton.CommandButtonKind.ACTION_ONLY); + RibbonApplicationMenuEntryPrimary exitbtn + = new RibbonApplicationMenuEntryPrimary( + getRibbonIcon("closeall"), + "Exit", + new ActionListener() { + @Override + public void actionPerformed(ActionEvent evt) { + maingui.dispatchEvent(new WindowEvent(maingui, + WindowEvent.WINDOW_CLOSING)); + } + }, + JCommandButton.CommandButtonKind.ACTION_ONLY); + RibbonApplicationMenuEntrySecondary newjsbtn + = new RibbonApplicationMenuEntrySecondary( + getTinyRibbonIcon("jsicon"), + "JavaScript", + new ActionListener() { + @Override + public void actionPerformed(ActionEvent evt) { + loadFrame(new Editor()); + } + }, + JCommandButton.CommandButtonKind.ACTION_ONLY); + RibbonApplicationMenuEntrySecondary newpybtn + = new RibbonApplicationMenuEntrySecondary( + getTinyRibbonIcon("pyicon"), + "Python", + new ActionListener() { + @Override + public void actionPerformed(ActionEvent evt) { + loadFrame(new Editor(true)); + } + }, + JCommandButton.CommandButtonKind.ACTION_ONLY); + RibbonApplicationMenuEntrySecondary newtaskbtn + = new RibbonApplicationMenuEntrySecondary( + getTinyRibbonIcon("taskicon"), + "Task List", + new ActionListener() { + @Override + public void actionPerformed(ActionEvent evt) { + loadFrame(new Tasks()); + } + }, + JCommandButton.CommandButtonKind.ACTION_ONLY); + RibbonApplicationMenuEntryPrimary newbtn + = new RibbonApplicationMenuEntryPrimary( + getRibbonIcon("newfile"), + "New", + null, + JCommandButton.CommandButtonKind.POPUP_ONLY); + openbtn = new RibbonApplicationMenuEntryPrimary( + getRibbonIcon("openfile"), + "Open", + new ActionListener() { + @Override + public void actionPerformed(ActionEvent evt) { + JFileChooser fc = new JFileChooser(); + FileFilter script + = new FileNameExtensionFilter("Script" + + "(syjs, sypy, js, py)", + "syjs", "sypy", "js", "py"); + FileFilter all + = new FileNameExtensionFilter("SyMAT File" + + "(syjs, sypy, js, py, sytt)", + "syjs", "sypy", "js", "py", "sytt"); + FileFilter tasklist + = new FileNameExtensionFilter("Task List (sytt)", + "sytt"); + fc.setFileFilter(all); + fc.addChoosableFileFilter(script); + fc.addChoosableFileFilter(tasklist); + int result = fc.showOpenDialog(maingui); + if (result == JFileChooser.APPROVE_OPTION) { + File f = fc.getSelectedFile(); + if (f.getName().endsWith(".sytt")) { + loadFrame(new Tasks(f)); + } else { + Editor ed = new Editor(); + ed.openFileFromName(f.getAbsolutePath()); + loadFrame(ed); + } + } + } + }, + JCommandButton.CommandButtonKind.ACTION_AND_POPUP_MAIN_ACTION); + + if (recent == null) { + RibbonApplicationMenuEntrySecondary blanksubbtn + = new RibbonApplicationMenuEntrySecondary( + null, "No recent files", null, + JCommandButton.CommandButtonKind.ACTION_ONLY); + blanksubbtn.setEnabled(false); + openbtn.addSecondaryMenuGroup("Recent Files", blanksubbtn); + } else { + openbtn.addSecondaryMenuGroup("Recent Files", recent); + } + newbtn.addSecondaryMenuGroup("Code File", newjsbtn, newpybtn); + newbtn.addSecondaryMenuGroup("Other", newtaskbtn); + + RibbonApplicationMenuEntryFooter displaybtn + = new RibbonApplicationMenuEntryFooter( + getTinyRibbonIcon("settings"), + "Settings", + new ActionListener() { + @Override + public void actionPerformed(ActionEvent evt) { + loadFrame(new Settings()); + } + }); + + RibbonApplicationMenuEntryPrimary blankbtn + = new RibbonApplicationMenuEntryPrimary( + null, "", null, + JCommandButton.CommandButtonKind.ACTION_ONLY); + blankbtn.setEnabled(false); + + RibbonApplicationMenu menu = new RibbonApplicationMenu(); + menu.addMenuEntry(newbtn); + menu.addMenuEntry(openbtn); + menu.addMenuSeparator(); + menu.addMenuEntry(helpbtn); + menu.addMenuEntry(cascadebtn); + menu.addMenuSeparator(); + menu.addMenuEntry(exitbtn); + menu.addFooterEntry(displaybtn); + + menu.addMenuEntry(blankbtn); + menu.addMenuEntry(blankbtn); + menu.addMenuEntry(blankbtn); + menu.addMenuEntry(blankbtn); + + maingui.getRibbon().setApplicationMenu(menu); + maingui.getRibbon().setApplicationMenuRichTooltip( + new RichTooltip("SyMAT Menu", + "Create files, open documents, " + + "get help, and change settings") + ); + } + + /** + * (Re)load recent file lists from storage. + */ + public static void loadRecentFiles() { + String files = PrefStorage.getSetting("recentfiles"); + if (files.equals("")) { + loadRibbonMenu(null); + recentFileList.setListData(new String[0]); + return; + } + String[] fileList = files.split("\n"); + int neededLength = 0; + for (String file : fileList) { + if ((new File(file)).isFile()) { + neededLength++; + } + } + if (neededLength > 10) { + neededLength = 10; + } + KeyValListItem[] items = new KeyValListItem[neededLength]; + int i = 0; + RibbonApplicationMenuEntrySecondary[] recentmenu + = new RibbonApplicationMenuEntrySecondary[fileList.length]; + for (String f : fileList) { + File file = new File(f); + if (file.isFile() && i < neededLength) { + items[i] = new KeyValListItem(file.getName(), file.getPath()); + recentmenu[i] = (new RibbonApplicationMenuEntrySecondary( + null, + file.getName(), + new ActionListener() { + final String path = file.getPath(); + + @Override + public void actionPerformed(ActionEvent evt) { + Editor edit = new Editor(); + edit.openFileFromName(path); + loadFrame(edit); + } + }, + JCommandButton.CommandButtonKind.ACTION_ONLY)); + i++; + } + } + + loadRibbonMenu(recentmenu); + recentFileList.setListData(items); + + // Re-save list to remove bad entries + String list = ""; + for (KeyValListItem item : items) { + list += item.getValue() + "\n"; + } + PrefStorage.saveSetting("recentfiles", list); + } + + /** + * Add a file to the recent files lists. + * + * @param file The file path. + */ + public static void addRecentFile(String file) { + file = (new File(file)).getAbsolutePath(); + String files = PrefStorage.getSetting("recentfiles"); + String[] fileList = files.split("\n"); + for (int i = 0; i < fileList.length; i++) { + if (fileList[i].trim().equals(file)) { + fileList[i] = ""; + } + } + files = file + "\n"; + for (String f : fileList) { + if (!f.trim().equals("")) { + files += f + "\n"; + } + } + PrefStorage.saveSetting("recentfiles", files); + PrefStorage.save(); + loadRecentFiles(); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + jMenuItem1 = new javax.swing.JMenuItem(); + mainPane = mainPane = new javax.swing.JDesktopPane() { + @Override + protected void paintComponent(Graphics g) { + super.paintComponent(g); + if (PrefStorage.getSetting("theme").equals("dark")) { + g.setColor(Color.DARK_GRAY); + } else { + g.setColor(Color.LIGHT_GRAY); + } + g.fillRect(0, 0, getWidth(), getHeight()); + } + } + ; + jLabel2 = new javax.swing.JLabel(); + recentItemsPanel = new javax.swing.JPanel(); + jScrollPane1 = new javax.swing.JScrollPane(); + recentFileList = new javax.swing.JList(); + recentFileBtn = new javax.swing.JButton(); + recentItemsTitle = new javax.swing.JLabel(); + appPanel = new javax.swing.JPanel(); + + jMenuItem1.setText("jMenuItem1"); + + setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE); + setTitle("SyMAT"); + setMinimumSize(new java.awt.Dimension(640, 540)); + addComponentListener(new java.awt.event.ComponentAdapter() { + public void componentShown(java.awt.event.ComponentEvent evt) { + formComponentShown(evt); + } + }); + + mainPane.setBackground(new java.awt.Color(204, 204, 204)); + mainPane.setAutoscrolls(true); + mainPane.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR)); + mainPane.setOpaque(false); + + jLabel2.setFont(Main.ubuntuRegular.deriveFont(48.0F)); + jLabel2.setForeground(new java.awt.Color(153, 153, 153)); + jLabel2.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); + jLabel2.setText("SyMAT"); + jLabel2.setVerticalAlignment(javax.swing.SwingConstants.BOTTOM); + + recentItemsPanel.setBorder(javax.swing.BorderFactory.createEtchedBorder()); + recentItemsPanel.setForeground(new java.awt.Color(153, 153, 153)); + recentItemsPanel.setMaximumSize(new java.awt.Dimension(160, 273)); + recentItemsPanel.setOpaque(false); + + jScrollPane1.setMinimumSize(new java.awt.Dimension(23, 206)); + jScrollPane1.setName(""); // NOI18N + + recentFileList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); + recentFileList.addMouseListener(new java.awt.event.MouseAdapter() { + public void mouseClicked(java.awt.event.MouseEvent evt) { + recentFileListMouseClicked(evt); + } + }); + recentFileList.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() { + public void mouseMoved(java.awt.event.MouseEvent evt) { + recentFileListMouseMoved(evt); + } + }); + jScrollPane1.setViewportView(recentFileList); + + recentFileBtn.setIcon(new javax.swing.ImageIcon(getClass().getResource("/net/apocalypselabs/symat/icons/openfile.png"))); // NOI18N + recentFileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + recentFileBtnActionPerformed(evt); + } + }); + + recentItemsTitle.setFont(new java.awt.Font("Tahoma", 1, 12)); // NOI18N + recentItemsTitle.setForeground(new java.awt.Color(102, 102, 102)); + recentItemsTitle.setText(" Recent Files"); + recentItemsTitle.setOpaque(true); + recentItemsTitle.addMouseListener(new java.awt.event.MouseAdapter() { + public void mouseClicked(java.awt.event.MouseEvent evt) { + recentItemsTitleMouseClicked(evt); + } + }); + + javax.swing.GroupLayout recentItemsPanelLayout = new javax.swing.GroupLayout(recentItemsPanel); + recentItemsPanel.setLayout(recentItemsPanelLayout); + recentItemsPanelLayout.setHorizontalGroup( + recentItemsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(recentItemsPanelLayout.createSequentialGroup() + .addGroup(recentItemsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(recentItemsPanelLayout.createSequentialGroup() + .addGap(97, 97, 97) + .addComponent(recentFileBtn)) + .addGroup(recentItemsPanelLayout.createSequentialGroup() + .addContainerGap() + .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 136, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addComponent(recentItemsTitle, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + ); + recentItemsPanelLayout.setVerticalGroup( + recentItemsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(recentItemsPanelLayout.createSequentialGroup() + .addComponent(recentItemsTitle) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 357, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(recentFileBtn) + .addContainerGap()) + ); + + appPanel.setOpaque(false); + appPanel.setLayout(new java.awt.GridBagLayout()); + + javax.swing.GroupLayout mainPaneLayout = new javax.swing.GroupLayout(mainPane); + mainPane.setLayout(mainPaneLayout); + mainPaneLayout.setHorizontalGroup( + mainPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, mainPaneLayout.createSequentialGroup() + .addContainerGap() + .addComponent(appPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(mainPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) + .addComponent(recentItemsPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jLabel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap()) + ); + mainPaneLayout.setVerticalGroup( + mainPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(mainPaneLayout.createSequentialGroup() + .addContainerGap() + .addGroup(mainPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(appPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(mainPaneLayout.createSequentialGroup() + .addComponent(recentItemsPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 84, Short.MAX_VALUE) + .addComponent(jLabel2))) + .addContainerGap()) + ); + mainPane.setLayer(jLabel2, javax.swing.JLayeredPane.DEFAULT_LAYER); + mainPane.setLayer(recentItemsPanel, javax.swing.JLayeredPane.DEFAULT_LAYER); + mainPane.setLayer(appPanel, javax.swing.JLayeredPane.DEFAULT_LAYER); + + getContentPane().add(mainPane, java.awt.BorderLayout.CENTER); + + pack(); + }// //GEN-END:initComponents + + private void formComponentShown(java.awt.event.ComponentEvent evt) {//GEN-FIRST:event_formComponentShown + setLocationRelativeTo(null); + }//GEN-LAST:event_formComponentShown + + private void recentFileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_recentFileBtnActionPerformed + if (recentFileList.getSelectedValue() == null) { + return; + } + KeyValListItem file = (KeyValListItem) recentFileList.getSelectedValue(); + if (file.isEmpty()) { + return; + } + Editor edit = new Editor(); + Debug.println(file.getValue()); + edit.openFileFromName(file.getValue()); + loadFrame(edit); + }//GEN-LAST:event_recentFileBtnActionPerformed + + private void recentFileListMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_recentFileListMouseClicked + if (evt.getClickCount() == 2) { + recentFileBtnActionPerformed(null); + } + }//GEN-LAST:event_recentFileListMouseClicked + + private void recentFileListMouseMoved(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_recentFileListMouseMoved + try { + ListModel m = recentFileList.getModel(); + int index = recentFileList.locationToIndex(evt.getPoint()); + if (index > -1) { + recentFileList.setToolTipText( + ((KeyValListItem) m.getElementAt(index)).getValue()); + } + } catch (Exception ex) { + // This feature is optional. Just skip it if it's broken. + recentFileList.setToolTipText(""); + } + }//GEN-LAST:event_recentFileListMouseMoved + + private void recentItemsTitleMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_recentItemsTitleMouseClicked + + }//GEN-LAST:event_recentItemsTitleMouseClicked + + /** + * Adds the given JInternalFrame to the mainPane. Automatically does layout + * and sets visible (if show==true). + * + * @param frame The frame + * @param show Should the frame be visible? + */ + public static void loadFrame(JInternalFrame frame, boolean show) { + int w = frame.getWidth(); + int h = frame.getHeight(); + int pw = mainPane.getWidth(); + int ph = mainPane.getHeight(); + if (frame.isResizable()) { + if (h > ph) { + h = ph; + } + if (w > pw) { + w = pw; + } + frame.setSize(w, h); + } + mainPane.add(frame); + frame.setLocation( + (pw / 2) - (w / 2), + (ph / 2) - (h / 2)); + if (frame.getLocation().y < 0) { + frame.setLocation(frame.getLocation().x, 0); + } + if (show) { + frame.setVisible(true); + } + } + + /** + * Adds the given JInternalFrame to the mainPane. Automatically does layout + * and sets visible. + * + * @param frame The frame + */ + public static void loadFrame(JInternalFrame frame) { + loadFrame(frame, true); + } + + /** + * Cascade all the frames in a stack. Somehow reverses the order each time + * around, I have no idea why but it's a "feature" now! + */ + public static void cascade() { + JInternalFrame[] frames = mainPane.getAllFrames(); + int x = 12; + int y = 24; + Debug.println("Cascading " + frames.length + " frames..."); + for (int i = 0; i < frames.length; i++) { + if (frames[i].isVisible()) { + Debug.println("Frame: " + + frames[i].getTitle() + + ", Times: " + i + + ", Xpos: " + x * i + + ", Ypos: " + y * i); + frames[i].setBounds(x * i, + y * i, + frames[i].getWidth(), + frames[i].getHeight()); + frames[i].toFront(); + } + } + } + + /** + * @param args the command line arguments + */ + public static void main(String args[]) { + /* Set the Nimbus look and feel */ + // + /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel. + * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html + */ + + try { + for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) { + if ("Nimbus".equals(info.getName())) { + UIManager.setLookAndFeel(info.getClassName()); + break; + } + } + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | javax.swing.UnsupportedLookAndFeelException e) { + java.util.logging.Logger.getLogger(Main.class.getName()).log(java.util.logging.Level.SEVERE, null, e); + } + // + // + // + // + + try { + // Ubuntu font for prettifying + ubuntuRegular = Font.createFont(Font.TRUETYPE_FONT, Main.class. + getResourceAsStream("/Ubuntu-R.ttf")); + } catch (FontFormatException | IOException ex) { + ubuntuRegular = Font.getFont(Font.SANS_SERIF); + System.err.println("Error loading fonts: " + ex.getMessage()); + } catch (Exception ex) { + ubuntuRegular = Font.getFont(Font.SANS_SERIF); + System.err.println("Error loading fonts: " + ex.getMessage()); + } + + // Set icon + String[] sizes = {"16", "24", "32", "48", "64", "96", "128", "256", "512"}; + for (String s : sizes) { + symatlogo.add(new ImageIcon( + Main.class.getResource(s + "x" + s + ".png")).getImage()); + } + + // Command line args + for (String arg : args) { + switch (arg) { + case "skippython": + skipPython = true; + break; + case "skipeditor": + skipEditor = true; + break; + case "quickstart": + skipPython = true; + skipEditor = true; + break; + case "licensereset": + PrefStorage.saveSetting("license", ""); + break; + default: + argfile = arg; + break; + } + } + + SingleInstanceClient sicli = new SingleInstanceClient(argfile); + + try { + new SingleInstanceServer().start(); + } catch (IOException ex) { + Debug.printerr("Cannot start instance listener:\n\n"); + Debug.stacktrace(ex); + } + + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + new JFXPanel(); // this will prepare JavaFX toolkit and environment + Platform.runLater(new Runnable() { + @Override + public void run() { + Platform.setImplicitExit(false); + } + }); + } + }); + + + /* Create and display the form */ + java.awt.EventQueue.invokeLater(() -> { + new SplashScreen().setVisible(true); + }); + } + + public static JCommandButton shellbtn + = new JCommandButton("Shell", getRibbonIcon("shell")); + public static JCommandButton editorbtn + = new JCommandButton("Editor", getRibbonIcon("editor")); + public static JCommandButton graphbtn + = new JCommandButton("Graph", getRibbonIcon("graph")); + public static JCommandButton notepadbtn + = new JCommandButton("Notepad", getRibbonIcon("notepad")); + public static JCommandButton wikibtn + = new JCommandButton("Wiki", getRibbonIcon("wiki")); + public static JCommandButton forumbtn + = new JCommandButton("Forum", getRibbonIcon("forum")); + public static JCommandButton padsbtn + = new JCommandButton("Pads", getRibbonIcon("pads")); + public static JCommandButton tasksbtn + = new JCommandButton("Tasks", getRibbonIcon("tasks")); + public static JCommandButton installpluginbtn + = new JCommandButton("Install", getRibbonIcon("installplugin")); + public static RibbonApplicationMenuEntryPrimary openbtn; + + // Variables declaration - do not modify//GEN-BEGIN:variables + public static javax.swing.JPanel appPanel; + public static javax.swing.JLabel jLabel2; + public static javax.swing.JMenuItem jMenuItem1; + public static javax.swing.JScrollPane jScrollPane1; + public static javax.swing.JDesktopPane mainPane; + public static javax.swing.JButton recentFileBtn; + public static javax.swing.JList recentFileList; + public static javax.swing.JPanel recentItemsPanel; + public static javax.swing.JLabel recentItemsTitle; + // End of variables declaration//GEN-END:variables +} diff --git a/src/net/apocalypselabs/symat/SplashScreen.java b/src/net/apocalypselabs/symat/SplashScreen.java index 81c3824..54bb5e3 100644 --- a/src/net/apocalypselabs/symat/SplashScreen.java +++ b/src/net/apocalypselabs/symat/SplashScreen.java @@ -1,279 +1,279 @@ -/* - * CODE LICENSE ===================== - * Copyright (c) 2015, Apocalypse Laboratories - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation and/or - * other materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors - * may be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * 4. You adhere to the Media License detailed below. If you do not, this license - * is automatically revoked and you must purge all copies of the software you - * possess, in source or binary form. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * MEDIA LICENSE ==================== - * All images and other graphical files (the "graphics") included with this - * software are copyright (c) 2015 Apocalypse Laboratories. You may not distribute - * the graphics or any program, source code repository, or other digital storage - * media containing them without written permission from Apocalypse Laboratories. - * This ban on distribution only applies to publicly available systems. - * A password-protected network file share, USB drive, or other storage scheme that - * cannot be easily accessed by the public is generally allowed. If in doubt, - * contact Apocalypse Laboratories. If Apocalypse Laboratories allows or denies - * you permission, that decision is considered final and binding. - */ -package net.apocalypselabs.symat; - -import java.awt.Color; -import java.io.BufferedReader; -import java.io.File; -import java.io.FilenameFilter; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.lang.reflect.Method; -import java.net.URL; -import java.net.URLClassLoader; -import javax.swing.SwingUtilities; -import static net.apocalypselabs.symat.Main.API_URL; -import static net.apocalypselabs.symat.Main.APP_CODE; -import static net.apocalypselabs.symat.Main.VERSION_NAME; - -/** - * - * @author Skylar - */ -public class SplashScreen extends javax.swing.JFrame { - - /** - * Creates new form SplashScreen - */ - public SplashScreen() { - initComponents(); - setBackground(new Color(255, 255, 255, 0)); - setIconImages(Main.symatlogo); - setLocationRelativeTo(null); - } - - /** - * This method is called from within the constructor to initialize the form. - * WARNING: Do NOT modify this code. The content of this method is always - * regenerated by the Form Editor. - */ - @SuppressWarnings("unchecked") - // //GEN-BEGIN:initComponents - private void initComponents() { - - jLayeredPane1 = new javax.swing.JLayeredPane(); - dispLabel = new javax.swing.JLabel(); - jLabel1 = new javax.swing.JLabel(); - jLabel2 = new javax.swing.JLabel(); - jLabel3 = new javax.swing.JLabel(); - jLabel4 = new javax.swing.JLabel(); - - setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); - setTitle("SyMAT"); - setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR)); - setMaximumSize(new java.awt.Dimension(500, 400)); - setMinimumSize(new java.awt.Dimension(500, 400)); - setUndecorated(true); - setPreferredSize(new java.awt.Dimension(500, 400)); - setResizable(false); - setType(java.awt.Window.Type.POPUP); - addComponentListener(new java.awt.event.ComponentAdapter() { - public void componentShown(java.awt.event.ComponentEvent evt) { - formComponentShown(evt); - } - }); - - jLayeredPane1.setBackground(new java.awt.Color(255, 255, 255)); - - dispLabel.setFont(net.apocalypselabs.symat.Main.ubuntuRegular.deriveFont(14.0F)); - dispLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); - dispLabel.setText("Loading..."); - dispLabel.setHorizontalTextPosition(javax.swing.SwingConstants.LEFT); - dispLabel.setMaximumSize(new java.awt.Dimension(400, 320)); - jLayeredPane1.add(dispLabel); - dispLabel.setBounds(140, 280, 220, 70); - - jLabel1.setFont(net.apocalypselabs.symat.Main.ubuntuRegular.deriveFont(36.0F)); - jLabel1.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); - jLabel1.setText(""+net.apocalypselabs.symat.Main.SYMAT+" "+net.apocalypselabs.symat.Main.VERSION_NAME+""); - jLayeredPane1.add(jLabel1); - jLabel1.setBounds(100, 220, 300, 50); - jLayeredPane1.setLayer(jLabel1, javax.swing.JLayeredPane.POPUP_LAYER); - - jLabel2.setIcon(new javax.swing.ImageIcon(getClass().getResource("/net/apocalypselabs/symat/images/splashscreen.png"))); // NOI18N - jLabel2.setVerticalAlignment(javax.swing.SwingConstants.TOP); - jLayeredPane1.add(jLabel2); - jLabel2.setBounds(0, 0, 500, 400); - - jLabel3.setFont(net.apocalypselabs.symat.Main.ubuntuRegular.deriveFont(12.0F)); - jLabel3.setHorizontalAlignment(javax.swing.SwingConstants.LEFT); - jLabel3.setText("Apocalypse Laboratories"); - jLayeredPane1.add(jLabel3); - jLabel3.setBounds(10, 370, 250, 30); - jLayeredPane1.setLayer(jLabel3, javax.swing.JLayeredPane.POPUP_LAYER); - - jLabel4.setFont(net.apocalypselabs.symat.Main.ubuntuRegular.deriveFont(12.0F)); - jLabel4.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); - jLabel4.setText("symatapp.com"); - jLabel4.setMaximumSize(new java.awt.Dimension(118, 14)); - jLabel4.setMinimumSize(new java.awt.Dimension(118, 14)); - jLabel4.setPreferredSize(new java.awt.Dimension(118, 14)); - jLayeredPane1.add(jLabel4); - jLabel4.setBounds(380, 370, 110, 30); - jLayeredPane1.setLayer(jLabel4, javax.swing.JLayeredPane.POPUP_LAYER); - - getContentPane().add(jLayeredPane1, java.awt.BorderLayout.CENTER); - - pack(); - }// //GEN-END:initComponents - - private void formComponentShown(java.awt.event.ComponentEvent evt) {//GEN-FIRST:event_formComponentShown - new Loader().start(); - }//GEN-LAST:event_formComponentShown - - /** - * Bootstrapping everything. - */ - private class Loader extends Thread { - - @Override - public void run() { - setProgress("Starting up..."); - if (PrefStorage.getSetting("quickstart").equals("yes")) { - Main.skipPython = true; - Main.skipEditor = true; - } - if (!Main.skipPython) { - // Python laggggsss when used for first time, this fixes the wait later. - System.out.println("Warming up Python engine, to skip run with argument 'skippython'"); - setProgress("Initializing code engine..."); - try { - CodeRunner python = new CodeRunner(true); - } catch (Exception ex) { - // Ignore - } - } - - if (!Main.skipEditor) { - System.out.println("Preparing editor, to skip run with argument 'skipeditor'"); - setProgress("Preparing editor..."); - // Get editor going too - Editor edit = new Editor(); - } - - setProgress("Loading toolkits..."); - try { - String fsep = System.getProperty("file.separator"); - File dir = new File(System.getProperty("user.home") + fsep + ".symat" + fsep + "toolkits"); - dir.mkdirs(); - File[] files = dir.listFiles(new FilenameFilter() { - @Override - public boolean accept(File dir, String name) { - return name.endsWith(".jar"); - } - }); - for (File f : files) { - addSoftwareLibrary(f); - } - } catch (Exception ex) { - Debug.stacktrace(ex); - } - - if (!PrefStorage.getSetting("skipupdates").equals("yes")) { - setProgress("Checking for updates..."); - checkUpdates(); - } - - setProgress("Loading main interface..."); - Main main = new Main(); - setProgress("Done!"); - dispose(); - } - - // Thanks to http://stackoverflow.com/a/9460999/2534036 - private void addSoftwareLibrary(File file) throws Exception { - Method method = URLClassLoader.class.getDeclaredMethod("addURL", new Class[]{URL.class}); - method.setAccessible(true); - method.invoke(ClassLoader.getSystemClassLoader(), new Object[]{file.toURI().toURL()}); - Debug.println("Loaded toolkit " + file.getName()); - } - - private void checkUpdates() { - // Check for updates. - try { - Debug.println("Checking for updates..."); - URL url = new URL(API_URL + "version.php"); - InputStream is = url.openStream(); - BufferedReader br = new BufferedReader(new InputStreamReader(is)); - - String line = br.readLine(); - br.close(); - is.close(); - double version = Double.parseDouble(line.split("\\|")[0]); - if (version > APP_CODE) { - if (PrefStorage.getSetting("update-ignore") - .equals(VERSION_NAME + "|" + line.split("\\|")[1])) { - System.out.println("An update was found, " - + "but has been ignored by the user."); - } else { - Debug.println("Update available."); - Main.updateString = line.split("\\|")[1]; - Main.updateAvailable = true; - } - } else { - Debug.println("No updates found."); - } - } catch (Exception e) { - System.err.println("Fail: Cannot check update server. \n" - + " Assuming local copy up-to-date."); - Debug.stacktrace(e); - } - } - - /** - * Set the progress text. - * - * @param label The String to put on the label. - */ - private void setProgress(String label) { - final String lbl = label; - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - dispLabel.setText(lbl); - } - }); - } - } - // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JLabel dispLabel; - private javax.swing.JLabel jLabel1; - private javax.swing.JLabel jLabel2; - private javax.swing.JLabel jLabel3; - private javax.swing.JLabel jLabel4; - private javax.swing.JLayeredPane jLayeredPane1; - // End of variables declaration//GEN-END:variables -} +/* + * CODE LICENSE ===================== + * Copyright (c) 2015, Apocalypse Laboratories + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * 4. You adhere to the Media License detailed below. If you do not, this license + * is automatically revoked and you must purge all copies of the software you + * possess, in source or binary form. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * MEDIA LICENSE ==================== + * All images and other graphical files (the "graphics") included with this + * software are copyright (c) 2015 Apocalypse Laboratories. You may not distribute + * the graphics or any program, source code repository, or other digital storage + * media containing them without written permission from Apocalypse Laboratories. + * This ban on distribution only applies to publicly available systems. + * A password-protected network file share, USB drive, or other storage scheme that + * cannot be easily accessed by the public is generally allowed. If in doubt, + * contact Apocalypse Laboratories. If Apocalypse Laboratories allows or denies + * you permission, that decision is considered final and binding. + */ +package net.apocalypselabs.symat; + +import java.awt.Color; +import java.io.BufferedReader; +import java.io.File; +import java.io.FilenameFilter; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.lang.reflect.Method; +import java.net.URL; +import java.net.URLClassLoader; +import javax.swing.SwingUtilities; +import static net.apocalypselabs.symat.Main.API_URL; +import static net.apocalypselabs.symat.Main.APP_CODE; +import static net.apocalypselabs.symat.Main.VERSION_NAME; + +/** + * + * @author Skylar + */ +public class SplashScreen extends javax.swing.JFrame { + + /** + * Creates new form SplashScreen + */ + public SplashScreen() { + initComponents(); + setBackground(new Color(255, 255, 255, 0)); + setIconImages(Main.symatlogo); + setLocationRelativeTo(null); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + jLayeredPane1 = new javax.swing.JLayeredPane(); + dispLabel = new javax.swing.JLabel(); + jLabel1 = new javax.swing.JLabel(); + jLabel2 = new javax.swing.JLabel(); + jLabel3 = new javax.swing.JLabel(); + jLabel4 = new javax.swing.JLabel(); + + setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); + setTitle("SyMAT"); + setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR)); + setMaximumSize(new java.awt.Dimension(500, 400)); + setMinimumSize(new java.awt.Dimension(500, 400)); + setUndecorated(true); + setPreferredSize(new java.awt.Dimension(500, 400)); + setResizable(false); + setType(java.awt.Window.Type.POPUP); + addComponentListener(new java.awt.event.ComponentAdapter() { + public void componentShown(java.awt.event.ComponentEvent evt) { + formComponentShown(evt); + } + }); + + jLayeredPane1.setBackground(new java.awt.Color(255, 255, 255)); + + dispLabel.setFont(net.apocalypselabs.symat.Main.ubuntuRegular.deriveFont(14.0F)); + dispLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); + dispLabel.setText("Loading..."); + dispLabel.setHorizontalTextPosition(javax.swing.SwingConstants.LEFT); + dispLabel.setMaximumSize(new java.awt.Dimension(400, 320)); + jLayeredPane1.add(dispLabel); + dispLabel.setBounds(140, 280, 220, 70); + + jLabel1.setFont(net.apocalypselabs.symat.Main.ubuntuRegular.deriveFont(36.0F)); + jLabel1.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); + jLabel1.setText(""+net.apocalypselabs.symat.Main.SYMAT+" "+net.apocalypselabs.symat.Main.VERSION_NAME+""); + jLayeredPane1.add(jLabel1); + jLabel1.setBounds(100, 220, 300, 50); + jLayeredPane1.setLayer(jLabel1, javax.swing.JLayeredPane.POPUP_LAYER); + + jLabel2.setIcon(new javax.swing.ImageIcon(getClass().getResource("/net/apocalypselabs/symat/images/splashscreen.png"))); // NOI18N + jLabel2.setVerticalAlignment(javax.swing.SwingConstants.TOP); + jLayeredPane1.add(jLabel2); + jLabel2.setBounds(0, 0, 500, 400); + + jLabel3.setFont(net.apocalypselabs.symat.Main.ubuntuRegular.deriveFont(12.0F)); + jLabel3.setHorizontalAlignment(javax.swing.SwingConstants.LEFT); + jLabel3.setText("Apocalypse Laboratories"); + jLayeredPane1.add(jLabel3); + jLabel3.setBounds(10, 370, 250, 30); + jLayeredPane1.setLayer(jLabel3, javax.swing.JLayeredPane.POPUP_LAYER); + + jLabel4.setFont(net.apocalypselabs.symat.Main.ubuntuRegular.deriveFont(12.0F)); + jLabel4.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING); + jLabel4.setText("symatapp.com"); + jLabel4.setMaximumSize(new java.awt.Dimension(118, 14)); + jLabel4.setMinimumSize(new java.awt.Dimension(118, 14)); + jLabel4.setPreferredSize(new java.awt.Dimension(118, 14)); + jLayeredPane1.add(jLabel4); + jLabel4.setBounds(380, 370, 110, 30); + jLayeredPane1.setLayer(jLabel4, javax.swing.JLayeredPane.POPUP_LAYER); + + getContentPane().add(jLayeredPane1, java.awt.BorderLayout.CENTER); + + pack(); + }// //GEN-END:initComponents + + private void formComponentShown(java.awt.event.ComponentEvent evt) {//GEN-FIRST:event_formComponentShown + new Loader().start(); + }//GEN-LAST:event_formComponentShown + + /** + * Bootstrapping everything. + */ + private class Loader extends Thread { + + @Override + public void run() { + setProgress("Starting up..."); + if (PrefStorage.getSetting("quickstart").equals("yes")) { + Main.skipPython = true; + Main.skipEditor = true; + } + if (!Main.skipPython) { + // Python laggggsss when used for first time, this fixes the wait later. + System.out.println("Warming up Python engine, to skip run with argument 'skippython'"); + setProgress("Initializing code engine..."); + try { + CodeRunner python = new CodeRunner(true); + } catch (Exception ex) { + // Ignore + } + } + + if (!Main.skipEditor) { + System.out.println("Preparing editor, to skip run with argument 'skipeditor'"); + setProgress("Preparing editor..."); + // Get editor going too + Editor edit = new Editor(); + } + + setProgress("Loading toolkits..."); + try { + String fsep = System.getProperty("file.separator"); + File dir = new File(System.getProperty("user.home") + fsep + ".symat" + fsep + "toolkits"); + dir.mkdirs(); + File[] files = dir.listFiles(new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + return name.endsWith(".jar"); + } + }); + for (File f : files) { + addSoftwareLibrary(f); + } + } catch (Exception ex) { + Debug.stacktrace(ex); + } + + if (!PrefStorage.getSetting("skipupdates").equals("yes")) { + setProgress("Checking for updates..."); + checkUpdates(); + } + + setProgress("Loading main interface..."); + Main main = new Main(); + setProgress("Done!"); + dispose(); + } + + // Thanks to http://stackoverflow.com/a/9460999/2534036 + private void addSoftwareLibrary(File file) throws Exception { + Method method = URLClassLoader.class.getDeclaredMethod("addURL", new Class[]{URL.class}); + method.setAccessible(true); + method.invoke(ClassLoader.getSystemClassLoader(), new Object[]{file.toURI().toURL()}); + Debug.println("Loaded toolkit " + file.getName()); + } + + private void checkUpdates() { + // Check for updates. + try { + Debug.println("Checking for updates..."); + URL url = new URL(API_URL + "version.php"); + InputStream is = url.openStream(); + BufferedReader br = new BufferedReader(new InputStreamReader(is)); + + String line = br.readLine(); + br.close(); + is.close(); + double version = Double.parseDouble(line.split("\\|")[0]); + if (version > APP_CODE) { + if (PrefStorage.getSetting("update-ignore") + .equals(VERSION_NAME + "|" + line.split("\\|")[1])) { + System.out.println("An update was found, " + + "but has been ignored by the user."); + } else { + Debug.println("Update available."); + Main.updateString = line.split("\\|")[1]; + Main.updateAvailable = true; + } + } else { + Debug.println("No updates found."); + } + } catch (Exception e) { + System.err.println("Fail: Cannot check update server. \n" + + " Assuming local copy up-to-date."); + Debug.stacktrace(e); + } + } + + /** + * Set the progress text. + * + * @param label The String to put on the label. + */ + private void setProgress(String label) { + final String lbl = label; + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + dispLabel.setText(lbl); + } + }); + } + } + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JLabel dispLabel; + private javax.swing.JLabel jLabel1; + private javax.swing.JLabel jLabel2; + private javax.swing.JLabel jLabel3; + private javax.swing.JLabel jLabel4; + private javax.swing.JLayeredPane jLayeredPane1; + // End of variables declaration//GEN-END:variables +} diff --git a/src/net/apocalypselabs/symat/functions.js b/src/net/apocalypselabs/symat/functions.js index 50482b2..bbf7bcf 100644 --- a/src/net/apocalypselabs/symat/functions.js +++ b/src/net/apocalypselabs/symat/functions.js @@ -1,32 +1,32 @@ -/*function mtimes(a,b) { - var m = SyMAT_Functions.$mtimes(a,b); - var out; - for (var i = 0; i < m.length; i++) { - for (var j = 0; j < m[i].length; j++) { - out[i][j] = m[i][j]; - } - } - return out; -} - -function mpower(a,b) { - var m = SyMAT_Functions.$mpower(a,b); - var out; - for (var i = 0; i < m.length; i++) { - for (var j = 0; j < m[i].length; j++) { - out[i][j] = m[i][j]; - } - } - return out; -} - -function minvert(a) { - var m = SyMAT_Functions.$minvert(a); - var out; - for (var i = 0; i < m.length; i++) { - for (var j = 0; j < m[i].length; j++) { - out[i][j] = m[i][j]; - } - } - return out; +/*function mtimes(a,b) { + var m = SyMAT_Functions.$mtimes(a,b); + var out; + for (var i = 0; i < m.length; i++) { + for (var j = 0; j < m[i].length; j++) { + out[i][j] = m[i][j]; + } + } + return out; +} + +function mpower(a,b) { + var m = SyMAT_Functions.$mpower(a,b); + var out; + for (var i = 0; i < m.length; i++) { + for (var j = 0; j < m[i].length; j++) { + out[i][j] = m[i][j]; + } + } + return out; +} + +function minvert(a) { + var m = SyMAT_Functions.$minvert(a); + var out; + for (var i = 0; i < m.length; i++) { + for (var j = 0; j < m[i].length; j++) { + out[i][j] = m[i][j]; + } + } + return out; }*/ \ No newline at end of file diff --git a/src/net/apocalypselabs/symat/pretty.css b/src/net/apocalypselabs/symat/pretty.css index 803cb05..e67f0a0 100644 --- a/src/net/apocalypselabs/symat/pretty.css +++ b/src/net/apocalypselabs/symat/pretty.css @@ -1,26 +1,26 @@ -/* -Public domain. -*/ -.header { - -} -.com { - color: green; -} - -.kwd { - color: blue; -} - -.pln { - color: black; -} - -.lit { - color: #0099cc; -} - -.pun { - color: black; - font-weight: bold; +/* +Public domain. +*/ +.header { + +} +.com { + color: green; +} + +.kwd { + color: blue; +} + +.pln { + color: black; +} + +.lit { + color: #0099cc; +} + +.pun { + color: black; + font-weight: bold; } \ No newline at end of file