diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000000..b7d98e49dc
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,12 @@
+# Set the default behavior, in case people don't have core.autocrlf set.
+* text=auto
+
+# Files which should always be normalized and converted
+# to native line endings on checkout.
+*.java text
+*.pde text
+
+# Files that will always have CRLF line endings on checkout.
+*.bat eol=crlf
+build/macosx/jAppleMenuBar.url eol=crlf
+
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 0000000000..41534ed7ba
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1,2 @@
+github: processing
+custom: https://processingfoundation.org
diff --git a/.github/workflows/lock.yml b/.github/workflows/lock.yml
new file mode 100644
index 0000000000..5ed1e8ee84
--- /dev/null
+++ b/.github/workflows/lock.yml
@@ -0,0 +1,29 @@
+name: 'Lock Threads'
+
+on:
+ schedule:
+ - cron: '0 6 * * *'
+
+permissions:
+ contents: read
+
+jobs:
+ lock:
+ permissions:
+ issues: write
+ pull-requests: write
+ runs-on: ubuntu-latest
+ steps:
+ - uses: dessant/lock-threads@v2.0.1
+ with:
+ github-token: ${{ github.token }}
+ issue-lock-inactive-days: '30'
+ issue-lock-comment: >
+ This issue has been automatically locked. To avoid confusion
+ with reports that have already been resolved, closed issues
+ are automatically locked 30 days after the last comment.
+ Please open a new issue for related bugs.
+ pr-lock-comment: >
+ This pull request has been automatically locked.
+ Pull requests that have been closed are automatically
+ locked 30 days after the last comment.
diff --git a/.gitignore b/.gitignore
index 520999a25f..cd99249298 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,76 @@
.AppleDouble
._*
*~
+/build/shared/reference.zip
+
+# temporary, until we complete the move to IntelliJ
+*.iml
+/.idea
+
+# via https://github.com/github/gitignore/blob/master/Global/JetBrains.gitignore
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
+# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+
+# User-specific stuff
+.idea/**/workspace.xml
+.idea/**/tasks.xml
+.idea/**/usage.statistics.xml
+.idea/**/dictionaries
+.idea/**/shelf
+
+# Generated files
+.idea/**/contentModel.xml
+
+# Sensitive or high-churn files
+.idea/**/dataSources/
+.idea/**/dataSources.ids
+.idea/**/dataSources.local.xml
+.idea/**/sqlDataSources.xml
+.idea/**/dynamic.xml
+.idea/**/uiDesigner.xml
+.idea/**/dbnavigator.xml
+
+# Gradle
+.idea/**/gradle.xml
+.idea/**/libraries
+
+# Gradle and Maven with auto-import
+# When using Gradle or Maven with auto-import, you should exclude module files,
+# since they will be recreated, and may cause churn. Uncomment if using
+# auto-import.
+# .idea/modules.xml
+# .idea/*.iml
+# .idea/modules
+
+# CMake
+cmake-build-*/
+
+# Mongo Explorer plugin
+.idea/**/mongoSettings.xml
+
+# File-based project format
+*.iws
+
+# IntelliJ
+out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Cursive Clojure plugin
+.idea/replstate.xml
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
+
+# Editor-based Rest Client
+.idea/httpRequests
+
+# Android studio 3.1+ serialized cache file
+.idea/caches/build_file_checksums.ser
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000000..afb13c6f19
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,24 @@
+## Welcome to Processing!
+
+### Bug Report?
+
+We have a page on [troubleshooting](https://github.com/processing/processing/wiki/Troubleshooting) common problems. Check there first!
+
+We also host an [online forum](https://forum.processing.org) for coding questions, which is also helpful for general "getting started" queries.
+
+If you don't find an answer, please let us know by [filing an issue](https://github.com/processing/processing/issues). We can only fix the things we've heard about.
+
+Please keep the tone polite. This project is volunteer work done in our free time. We give it away at no cost. We do this because we think it's important for the community and enjoy it. Complaints that things *suck* are *annoying* or lectures about things that *must* be fixed are... weird things to hear from strangers at best, demotivating at worst.
+
+### Want to Help?
+
+Great! The number of contributors on this project is *tiny*, especially relative to the number of users. There are [only 2 or 3 people](https://github.com/processing/processing/graphs/contributors) who actively work on this repository, for instance. We need help!
+
+How to start:
+
+* Issues marked [help](https://github.com/processing/processing/issues?q=is%3Aissue+is%3Aopen+label%3Ahelp) are a good place to start, because they're something that's isolated enough that someone can jump into it without significant reworking of other code.
+* Mind the [style guidelines](https://github.com/processing/processing/wiki/Style-Guidelines) when submitting pull requests. Otherwise someone else will have to reformat your code so that it fits everything else (or we'll have to reject it if it'll take us too long to clean it up).
+
+### Other Details
+
+This document was hastily thrown together in an attempt to improve the bug reporting process. It needs more detail about our intent with the project, the community behind it, our values, and an explanation of how the code itself is designed.
\ No newline at end of file
diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md
new file mode 100644
index 0000000000..bc9287c602
--- /dev/null
+++ b/ISSUE_TEMPLATE.md
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+## Description
+
+
+
+## Expected Behavior
+
+
+
+## Current Behavior
+
+
+## Steps to Reproduce
+
+
+1.
+2.
+3.
+
+## Your Environment
+
+
+
+* Processing version:
+* Operating System and OS version:
+* Other information:
+
+## Possible Causes / Solutions
+
diff --git a/README.md b/README.md
index bf31bfd91c..ece7d3ab72 100644
--- a/README.md
+++ b/README.md
@@ -1,36 +1,48 @@
-Processing
-==========
-This is the official source code for the [Processing](http://processing.org) Development Environment (PDE),
-the “core” and the libraries that are included with the [download](http://processing.org/download).
-> Development of Processing 3 has started, so major changes are underway inside this repository. **If you need a stable version of the source, use the tag processing-0227-2.2.1.** Do not expect this code to be stable. Major changes include severe things like breaking libraries (due to chaining operations in PVector) or the removal of `Applet` as the base class for PApplet. Some of these will be sorted out before the release, others are simply being tested or are developments that are in-progress.
+>[!WARNING]
+> # Development has moved to [a new repository](https://github.com/processing/processing4/).
-> Update September 2014: java.awt.Applet is no longer the base class, which means lots of things may break (especially while we sort out the mess). You can use [the 3.0a4 tag](https://github.com/processing/processing/releases/tag/processing-0231-3.0a4) if you'd like the last “stable” alpha release.
+Since the release of Processing 3.5.4 in January 2020, development has continued in a new repository: [processing/processing4](https://github.com/processing/processing4/).
-If you have found a bug in the Processing software, you can file it here under the [“issues” tab](https://github.com/processing/processing/issues).
-If it relates to the [JavaScript](http://processingjs.org) version, please use [their issue tracker](https://processing-js.lighthouseapp.com/).
-All Android-related development has moved to its own repository [here](https://github.com/processing/processing-android),
-so issues with Android Mode, or with the Android version of the core library should be posted there instead.
+We chose to move to a new repository so that we could clean out old files accumulated over the last 20 years.
-The issues list has been imported from Google Code, so there are many spurious references
-amongst them since the numbering changed. Basically, any time you see references to
-changes made by [processing-bugs](https://github.com/processing-bugs), it may be somewhat suspect.
-Over time this will clean itself up as bugs are fixed and new issues are added from within Github.
-Help speed this process along by helping us!
+To report bugs or request features, please open a [new issue](https://github.com/processing/processing4/issues/new/choose) on the Processing 4 repository.
+
+
+
+
+~~Processing~~
+==========
-The [processing-docs](https://github.com/processing/processing-docs/) repository contains reference, examples, and the site.
-(Please use that link to file issues regarding the web site, the examples, or the reference.)
+~~This is the official source code for the [Processing](http://processing.org) Development Environment (PDE),
+the “core” and the libraries that are included with the [download](http://processing.org/download).~~
+
+~~__I've found a bug!__~~
+~~Let us know [here](https://github.com/processing/processing/issues) (after first checking if someone has already posted a similar problem).
+If it's a reference, web site, or examples issue, take that up with folks [here](https://github.com/processing/processing-docs/issues).
+There are also separate locations for [Android Mode](https://github.com/processing/processing-android/issues), or the [Video](https://github.com/processing/processing-video/issues) and [Sound](https://github.com/processing/processing-sound/issues) libraries.
+The [processing.js](http://processingjs.org) project is not affiliated with us, but you can find their issue tracker [here](https://github.com/processing-js/processing-js/issues).~~
+
+~~__Locked Issues__
+Where possible, I've started locking issues once resolved. This helps reduce the amount of noise from folks adding to an issue that's been closed for years. Because this project has existed for a long time and we have thousands of closed issues, lots of them may sound similar to an issue you're having. But if there's a new problem, it'll be missed if it's lost in a comment added to an already closed issue. I don't like to lock issues because it cuts off conversation, but it's better than legitimate problems being missed. Once an issue has been resolved for 30 days, it will automatically lock.~~
+
+~~__That [processing-bugs](https://github.com/processing-bugs) fella is suspicious.__
+The issues list has been imported from Google Code, so there are many spurious references
+amongst them since the numbering changed. Basically, any time you see references to
+changes made by [processing-bugs](https://github.com/processing-bugs), it may be somewhat suspect.
+Over time this will clean itself up as bugs are fixed and new issues are added from within GitHub.
+Help speed this process along by helping us!~~
+~~__Please help.__
The instructions for building the source [are here](https://github.com/processing/processing/wiki/Build-Instructions).
+Please help us fix problems, and if you're submitting code, following the [style guidelines](https://github.com/processing/processing/wiki/Style-Guidelines) helps save me a lot of time.~~
-Someday we'll also write code style guidelines, fix all these bugs,
-throw together hundreds of unit tests,
-and get rich off all this stuff that we're giving away for free.
+~~__And finally...__
+Someday we'll also fix all these bugs, throw together hundreds of unit tests, and get rich off all this stuff that we're giving away for free. But not today.~~
-But in the meantime, I ask for your patience,
-[participation](https://github.com/processing/processing/wiki/Project-List),
-and [patches](https://github.com/processing/processing/pulls).
+~~So in the meantime, I ask for your patience,
+[participation](https://github.com/processing/processing/wiki/Project-List),
+and [patches](https://github.com/processing/processing/pulls).~~
-Ben Fry, 3 February 2013
-Last updated 14 September 2014
+~~Ben Fry, 20 January 2019~~
diff --git a/app/.classpath b/app/.classpath
index e12f72e7e7..72c3737104 100644
--- a/app/.classpath
+++ b/app/.classpath
@@ -1,23 +1,13 @@
-
-
-
-
-
-
+
-
-
-
-
-
-
+
diff --git a/app/.gitignore b/app/.gitignore
index 51f7f5c15e..81e75864d6 100644
--- a/app/.gitignore
+++ b/app/.gitignore
@@ -1,3 +1,2 @@
bin
-generated
pde.jar
diff --git a/app/.settings/org.eclipse.jdt.core.prefs b/app/.settings/org.eclipse.jdt.core.prefs
index da7176c57b..af36b24305 100644
--- a/app/.settings/org.eclipse.jdt.core.prefs
+++ b/app/.settings/org.eclipse.jdt.core.prefs
@@ -5,9 +5,10 @@ org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annota
org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
-org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
@@ -92,8 +93,13 @@ org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disa
org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
-org.eclipse.jdt.core.compiler.source=1.6
+org.eclipse.jdt.core.compiler.source=1.8
+org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=false
+org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns=false
+org.eclipse.jdt.core.formatter.align_with_spaces=false
+org.eclipse.jdt.core.formatter.alignment_for_additive_operator=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=18
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
@@ -102,24 +108,39 @@ org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=18
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
org.eclipse.jdt.core.formatter.alignment_for_assignment=0
org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator=16
org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_loops=16
org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression_chain=0
org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=36
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0
+org.eclipse.jdt.core.formatter.alignment_for_logical_operator=16
org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_module_statements=16
org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator=16
+org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=18
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=18
+org.eclipse.jdt.core.formatter.alignment_for_relational_operator=0
org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_shift_operator=0
+org.eclipse.jdt.core.formatter.alignment_for_string_concatenation=16
org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_type_arguments=0
+org.eclipse.jdt.core.formatter.alignment_for_type_parameters=0
org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_after_last_class_body_declaration=0
org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.blank_lines_before_abstract_method=1
org.eclipse.jdt.core.formatter.blank_lines_before_field=1
org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
@@ -128,6 +149,7 @@ org.eclipse.jdt.core.formatter.blank_lines_before_method=1
org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
org.eclipse.jdt.core.formatter.blank_lines_before_package=0
org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
+org.eclipse.jdt.core.formatter.blank_lines_between_statement_group_in_switch=0
org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
@@ -137,32 +159,38 @@ org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped=false
+org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions=false
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
+org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position=false
org.eclipse.jdt.core.formatter.comment.format_block_comments=true
org.eclipse.jdt.core.formatter.comment.format_header=false
org.eclipse.jdt.core.formatter.comment.format_html=true
org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
-org.eclipse.jdt.core.formatter.comment.format_line_comments=false
+org.eclipse.jdt.core.formatter.comment.format_line_comments=true
org.eclipse.jdt.core.formatter.comment.format_source_code=true
org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
+org.eclipse.jdt.core.formatter.comment.indent_tag_description=false
org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_between_different_tags=do not insert
org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert
org.eclipse.jdt.core.formatter.comment.line_length=80
org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
org.eclipse.jdt.core.formatter.compact_else_if=true
-org.eclipse.jdt.core.formatter.continuation_indentation=1
-org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=1
+org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
-org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
+org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=false
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
@@ -175,6 +203,7 @@ org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
org.eclipse.jdt.core.formatter.indentation.size=2
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_member=insert
@@ -184,6 +213,7 @@ org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
@@ -197,11 +227,15 @@ org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_additive_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_default=insert
org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
@@ -228,9 +262,14 @@ org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declar
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_switch_case_expressions=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_after_logical_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_not_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
@@ -255,13 +294,20 @@ org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_relational_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
+org.eclipse.jdt.core.formatter.insert_space_after_shift_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation=insert
org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_additive_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_case=insert
+org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_default=insert
org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
@@ -305,9 +351,13 @@ org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_decla
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_switch_case_expressions=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_logical_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
@@ -344,9 +394,12 @@ org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not inser
org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_relational_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_shift_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation=insert
org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
@@ -358,20 +411,59 @@ org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_decla
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.join_lines_in_comments=true
org.eclipse.jdt.core.formatter.join_wrapped_lines=true
+org.eclipse.jdt.core.formatter.keep_annotation_declaration_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_anonymous_type_declaration_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_code_block_on_one_line=one_line_never
org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_enum_constant_declaration_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_enum_declaration_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_if_then_body_block_on_one_line=one_line_never
org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_lambda_body_block_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_loop_body_block_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_method_body_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_simple_getter_setter_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line=false
org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_type_declaration_on_one_line=one_line_never
org.eclipse.jdt.core.formatter.lineSplit=80
org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
-org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=true
+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.number_of_blank_lines_after_code_block=0
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_code_block=0
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_code_block=0
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_blank_lines_before_code_block=0
org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
+org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause=common_lines
org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
org.eclipse.jdt.core.formatter.tabulation.char=space
org.eclipse.jdt.core.formatter.tabulation.size=2
+org.eclipse.jdt.core.formatter.text_block_indentation=0
org.eclipse.jdt.core.formatter.use_on_off_tags=false
org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_additive_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false
org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_logical_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator=true
org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_before_relational_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_shift_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_string_concatenation=true
org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
diff --git a/app/.settings/org.eclipse.jdt.ui.prefs b/app/.settings/org.eclipse.jdt.ui.prefs
index 7f5ba1ed84..66aaa0890e 100644
--- a/app/.settings/org.eclipse.jdt.ui.prefs
+++ b/app/.settings/org.eclipse.jdt.ui.prefs
@@ -1,3 +1,3 @@
eclipse.preferences.version=1
formatter_profile=_processing
-formatter_settings_version=12
+formatter_settings_version=18
diff --git a/app/build.xml b/app/build.xml
old mode 100755
new mode 100644
index 4122ed0e8b..b6d97218ab
--- a/app/build.xml
+++ b/app/build.xml
@@ -1,53 +1,16 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
+
@@ -65,20 +28,24 @@
-
-
-
-
+
diff --git a/app/lib/com.ibm.icu_4.4.2.v20110823.jar b/app/lib/com.ibm.icu_4.4.2.v20110823.jar
deleted file mode 100644
index 18a293eb6b..0000000000
Binary files a/app/lib/com.ibm.icu_4.4.2.v20110823.jar and /dev/null differ
diff --git a/app/lib/jdi.jar b/app/lib/jdi.jar
deleted file mode 100644
index 373697ce45..0000000000
Binary files a/app/lib/jdi.jar and /dev/null differ
diff --git a/app/lib/jdimodel.jar b/app/lib/jdimodel.jar
deleted file mode 100644
index 04b5ba51f2..0000000000
Binary files a/app/lib/jdimodel.jar and /dev/null differ
diff --git a/app/lib/jna-platform.jar b/app/lib/jna-platform.jar
new file mode 100644
index 0000000000..d0fd2e4f52
Binary files /dev/null and b/app/lib/jna-platform.jar differ
diff --git a/app/lib/jna.jar b/app/lib/jna.jar
index 748adb001b..25243176ea 100644
Binary files a/app/lib/jna.jar and b/app/lib/jna.jar differ
diff --git a/app/lib/jna.txt b/app/lib/jna.txt
new file mode 100644
index 0000000000..4dbac83c25
--- /dev/null
+++ b/app/lib/jna.txt
@@ -0,0 +1,4 @@
+The JAR file is JNA 4.2.0
+
+You can find the corresponding file for Maven here:
+https://maven.java.net/content/repositories/releases/net/java/dev/jna/jna/4.2.0/
diff --git a/app/lib/org.eclipse.osgi_3.8.1.v20120830-144521.jar b/app/lib/org.eclipse.osgi_3.8.1.v20120830-144521.jar
deleted file mode 100644
index c152830e86..0000000000
Binary files a/app/lib/org.eclipse.osgi_3.8.1.v20120830-144521.jar and /dev/null differ
diff --git a/app/src/processing/app/About.java b/app/src/processing/app/About.java
deleted file mode 100644
index f034c0a74d..0000000000
--- a/app/src/processing/app/About.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package processing.app;
-
-import java.awt.Color;
-import java.awt.Dimension;
-import java.awt.Font;
-import java.awt.Frame;
-import java.awt.Graphics;
-import java.awt.Graphics2D;
-import java.awt.Image;
-import java.awt.RenderingHints;
-import java.awt.Window;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
-
-
-public class About extends Window {
- Image image;
- int width, height;
-
-
- public About(Frame frame) {
- super(frame);
-
- if (Toolkit.highResDisplay()) {
- image = Toolkit.getLibImage("about-2x.jpg"); //$NON-NLS-1$
- width = image.getWidth(null) / 2;
- height = image.getHeight(null) / 2;
- } else {
- image = Toolkit.getLibImage("about.jpg"); //$NON-NLS-1$
- width = image.getWidth(null);
- height = image.getHeight(null);
- }
-
- addMouseListener(new MouseAdapter() {
- public void mousePressed(MouseEvent e) {
- dispose();
- }
- });
-
- Dimension screen = Toolkit.getScreenSize();
- setBounds((screen.width-width)/2, (screen.height-height)/2, width, height);
- setVisible(true);
- }
-
-
- public void paint(Graphics g) {
- g.drawImage(image, 0, 0, width, height, null);
-
- Graphics2D g2 = (Graphics2D) g;
- g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
- RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
-
- g.setFont(new Font("SansSerif", Font.PLAIN, 11)); //$NON-NLS-1$
- g.setColor(Color.white);
- g.drawString(Base.getVersionName(), 50, 30);
- }
-}
\ No newline at end of file
diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java
index 4c76dc7b1e..5d9b0a114c 100644
--- a/app/src/processing/app/Base.java
+++ b/app/src/processing/app/Base.java
@@ -3,7 +3,8 @@
/*
Part of the Processing project - http://processing.org
- Copyright (c) 2004-14 Ben Fry and Casey Reas
+ Copyright (c) 2012-19 The Processing Foundation
+ Copyright (c) 2004-12 Ben Fry and Casey Reas
Copyright (c) 2001-04 Massachusetts Institute of Technology
This program is free software; you can redistribute it and/or
@@ -22,20 +23,29 @@
package processing.app;
-import java.awt.*;
-import java.awt.event.*;
+import java.awt.EventQueue;
+import java.awt.FileDialog;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
import java.io.*;
+import java.lang.reflect.InvocationTargetException;
import java.text.SimpleDateFormat;
import java.util.*;
-import java.util.List;
-import java.util.zip.*;
+import java.util.Map.Entry;
-import javax.swing.*;
-import javax.swing.tree.*;
+import javax.swing.JFileChooser;
+import javax.swing.JMenu;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.JPopupMenu;
+import javax.swing.tree.DefaultMutableTreeNode;
import processing.app.contrib.*;
+import processing.app.tools.Tool;
+import processing.app.ui.*;
import processing.core.*;
-import processing.mode.java.JavaMode;
+import processing.data.StringList;
+
/**
* The base class for the main processing application.
@@ -46,48 +56,17 @@
public class Base {
// Added accessors for 0218 because the UpdateCheck class was not properly
// updating the values, due to javac inlining the static final values.
- static private final int REVISION = 232;
+ static private final int REVISION = 271;
/** This might be replaced by main() if there's a lib/version.txt file. */
- static private String VERSION_NAME = "0232"; //$NON-NLS-1$
+ static private String VERSION_NAME = "0271"; //$NON-NLS-1$
/** Set true if this a proper release rather than a numbered revision. */
-// static private boolean RELEASE = false;
-
- /** True if heavy debugging error/log messages are enabled */
- static public boolean DEBUG = false;
-// static public boolean DEBUG = true;
-
- static HashMap platformNames =
- new HashMap();
- static {
- platformNames.put(PConstants.WINDOWS, "windows"); //$NON-NLS-1$
- platformNames.put(PConstants.MACOSX, "macosx"); //$NON-NLS-1$
- platformNames.put(PConstants.LINUX, "linux"); //$NON-NLS-1$
- }
-
- static HashMap platformIndices = new HashMap();
- static {
- platformIndices.put("windows", PConstants.WINDOWS); //$NON-NLS-1$
- platformIndices.put("macosx", PConstants.MACOSX); //$NON-NLS-1$
- platformIndices.put("linux", PConstants.LINUX); //$NON-NLS-1$
- }
- static Platform platform;
-
- /** How many bits this machine is */
- static int nativeBits;
- static {
- nativeBits = 32; // perhaps start with 32
- String bits = System.getProperty("sun.arch.data.model"); //$NON-NLS-1$
- if (bits != null) {
- if (bits.equals("64")) { //$NON-NLS-1$
- nativeBits = 64;
- }
- } else {
- // if some other strange vm, maybe try this instead
- if (System.getProperty("java.vm.name").contains("64")) { //$NON-NLS-1$ //$NON-NLS-2$
- nativeBits = 64;
- }
- }
- }
+
+ /**
+ * True if heavy debugging error/log messages are enabled. Set to true
+ * if an empty file named 'debug' is found in the settings folder.
+ * See implementation in createAndShowGUI().
+ */
+ static public boolean DEBUG;
static private boolean commandLine;
@@ -95,15 +74,7 @@ public class Base {
PreferencesFrame preferencesFrame;
// A single instance of the library manager window
- ContributionManagerDialog libraryManagerFrame;
- ContributionManagerDialog toolManagerFrame;
- ContributionManagerDialog modeManagerFrame;
- ContributionManagerDialog exampleManagerFrame;
- ContributionManagerDialog updateManagerFrame;
-
- // set to true after the first time the menu is built.
- // so that the errors while building don't show up again.
- boolean builtOnce;
+// ContributionManagerDialog contributionManagerFrame;
// Location for untitled items
static File untitledFolder;
@@ -123,13 +94,13 @@ public class Base {
/** The built-in modes. coreModes[0] will be considered the 'default'. */
private Mode[] coreModes;
- protected ArrayList modeContribs;
- protected ArrayList exampleContribs;
+ protected List modeContribs;
+ protected List exampleContribs;
private JMenu sketchbookMenu;
- private Recent recent;
+// private Recent recent;
// Used by handleOpen(), this saves the chooser to remember the directory.
// Doesn't appear to be necessary with the AWT native file dialog.
@@ -143,7 +114,35 @@ public class Base {
static public void main(final String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
- createAndShowGUI(args);
+ try {
+ createAndShowGUI(args);
+
+ } catch (Throwable t) {
+ // Windows Defender has been insisting on destroying each new
+ // release by removing core.jar and other files. Yay!
+ // https://github.com/processing/processing/issues/5537
+ if (Platform.isWindows()) {
+ String mess = t.getMessage();
+ String missing = null;
+ if (mess.contains("Could not initialize class com.sun.jna.Native")) {
+ missing = "jnidispatch.dll";
+ } else if (mess.contains("NoClassDefFoundError: processing/core/PApplet")) {
+ missing = "core.jar";
+ }
+ if (missing != null) {
+ Messages.showError("Necessary files are missing",
+ "A file required by Processing (" + missing + ") is missing.\n\n" +
+ "Make sure that you're not trying to run Processing from inside\n" +
+ "the .zip file you downloaded, and check that Windows Defender\n" +
+ "hasn't removed files from the Processing folder.\n\n" +
+ "(It sometimes flags parts of Processing as a trojan or virus.\n" +
+ "It is neither, but Microsoft has ignored our pleas for help.)", t);
+ }
+ }
+ Messages.showTrace("Unknown Problem",
+ "A serious error happened during startup. Please report:\n" +
+ "http://github.com/processing/processing/issues/new", t, true);
+ }
}
});
}
@@ -151,19 +150,31 @@ public void run() {
static private void createAndShowGUI(String[] args) {
try {
- File versionFile = getContentFile("lib/version.txt"); //$NON-NLS-1$
+ File versionFile = Platform.getContentFile("lib/version.txt");
if (versionFile.exists()) {
String version = PApplet.loadStrings(versionFile)[0];
if (!version.equals(VERSION_NAME)) {
VERSION_NAME = version;
-// RELEASE = true;
}
}
} catch (Exception e) {
e.printStackTrace();
}
- initPlatform();
+ Platform.init();
+ // call after Platform.init() because we need the settings folder
+ Console.startup();
+
+ // Set the debug flag based on a file being present in the settings folder
+ File debugFile = getSettingsFile("debug.txt");
+ /*
+ if (debugFile.isDirectory()) {
+ // if it's a directory, it's a leftover from older releases, clear it
+ Util.removeDir(debugFile);
+ } else*/
+ if (debugFile.exists()) {
+ DEBUG = true;
+ }
// Use native popups so they don't look so crappy on OS X
JPopupMenu.setDefaultLightWeightPopupEnabled(false);
@@ -172,7 +183,7 @@ static private void createAndShowGUI(String[] args) {
// because the platform has to be inited properly first.
// Make sure a full JDK is installed
- initRequirements();
+ //initRequirements();
// Load the languages
Language.init();
@@ -180,216 +191,203 @@ static private void createAndShowGUI(String[] args) {
// run static initialization that grabs all the prefs
Preferences.init();
- // Get the sketchbook path, and make sure it's set properly
- locateSketchbookFolder();
-
-// String filename = args.length > 1 ? args[0] : null;
if (!SingleInstance.alreadyRunning(args)) {
-// SingleInstance.startServer(platform);
-
// Set the look and feel before opening the window
try {
- platform.setLookAndFeel();
+ Platform.setLookAndFeel();
} catch (Exception e) {
-// String mess = e.getMessage();
-// if (!mess.contains("ch.randelshofer.quaqua.QuaquaLookAndFeel")) {
- log("Could not set the Look & Feel", e); //$NON-NLS-1$
-// }
+ Messages.loge("Could not set the Look & Feel", e); //$NON-NLS-1$
+ }
+
+ boolean sketchbookPrompt = false;
+ if (Preferences.getBoolean("welcome.show")) {
+ // only ask once about split sketchbooks
+ if (!Preferences.getBoolean("welcome.seen")) {
+ // Check if there's a 2.0 sketchbook present
+ String oldPath = Preferences.getOldSketchbookPath();
+ if (oldPath != null) {
+ String newPath = Preferences.getSketchbookPath();
+ // If newPath is null, this is the first run of any 3.x version
+ if (newPath == null) {
+ sketchbookPrompt = true;
+
+ } else if (oldPath.equals(newPath)) {
+ // If both exist and are identical, then the user has used
+ // pre-releases of 3.x and needs to be warned about the
+ // larger changes in this release.
+ sketchbookPrompt = true;
+ }
+ }
+ }
}
+ // Get the sketchbook path, and make sure it's set properly
+ locateSketchbookFolder();
+
// Create a location for untitled sketches
try {
- untitledFolder = Base.createTempFolder("untitled", "sketches", null);
+ untitledFolder = Util.createTempFolder("untitled", "sketches", null);
untitledFolder.deleteOnExit();
} catch (IOException e) {
- Base.showError("Trouble without a name",
- "Could not create a place to store untitled sketches.\n" +
- "That's gonna prevent us from continuing.", e);
+ Messages.showError("Trouble without a name",
+ "Could not create a place to store untitled sketches.\n" +
+ "That's gonna prevent us from continuing.", e);
}
- log("about to create base..."); //$NON-NLS-1$
+ Messages.log("About to create Base..."); //$NON-NLS-1$
try {
- Base base = new Base(args);
+ final Base base = new Base(args);
+ Messages.log("Base() constructor succeeded");
+
// Prevent more than one copy of the PDE from running.
SingleInstance.startServer(base);
+ // Needs to be shown after the first editor window opens, so that it
+ // shows up on top, and doesn't prevent an editor window from opening.
+ if (Preferences.getBoolean("welcome.show")) {
+ try {
+ new Welcome(base, sketchbookPrompt);
+ } catch (IOException e) {
+ Messages.showTrace("Unwelcoming",
+ "Please report this error to\n" +
+ "https://github.com/processing/processing/issues", e, false);
+ }
+ }
+
+ checkDriverBug();
+
} catch (Throwable t) {
- // Catch-all to hopefully pick up some of the weirdness we've been
- // running into lately.
- showBadnessTrace("We're off on the wrong foot",
- "An error occurred during startup.", t, true);
+ // Catch-all to pick up badness during startup.
+ if (t.getCause() != null) {
+ // Usually this is the more important piece of information. We'll
+ // show this one so that it's not truncated in the error window.
+ t = t.getCause();
+ }
+ Messages.showTrace("We're off on the wrong foot",
+ "An error occurred during startup.", t, true);
}
- log("done creating base..."); //$NON-NLS-1$
+ Messages.log("Done creating Base..."); //$NON-NLS-1$
}
}
- public static void setCommandLine() {
- commandLine = true;
+ // Remove this code in a couple months [fry 170211]
+ // https://github.com/processing/processing/issues/4853
+ // Or maybe not, if NVIDIA keeps doing this [fry 170423]
+ // https://github.com/processing/processing/issues/4997
+ static private void checkDriverBug() {
+ if (System.getProperty("os.name").contains("Windows 10")) {
+ new Thread(new Runnable() {
+ public void run() {
+ try {
+ Process p = Runtime.getRuntime().exec("powershell Get-WmiObject Win32_PnPSignedDriver| select devicename, driverversion | where {$_.devicename -like \\\"*nvidia*\\\"}");
+ BufferedReader reader = PApplet.createReader(p.getInputStream());
+ String line = null;
+ while ((line = reader.readLine()) != null) {
+ if (line.contains("3.7849")) {
+ EventQueue.invokeLater(new Runnable() {
+ public void run() {
+ Messages.showWarning("NVIDIA screwed up",
+ "Due to an NVIDIA bug, you need to update your graphics drivers,\n" +
+ "otherwise you won't be able to run any sketches. Update here:\n" +
+ "http://nvidia.custhelp.com/app/answers/detail/a_id/4378\n" +
+ "or read background about the issue at this link:\n" +
+ "https://github.com/processing/processing/issues/4853");
+ }
+ });
+ } else if (line.contains("3.8165")) {
+ EventQueue.invokeLater(new Runnable() {
+ public void run() {
+ Messages.showWarning("NVIDIA screwed up again",
+ "Due to an NVIDIA bug, you need to update your graphics drivers,\n" +
+ "otherwise you won't be able to run any sketches. Update here:\n" +
+ "http://nvidia.custhelp.com/app/answers/detail/a_id/4453/\n" +
+ "or read background about the issue at this link:\n" +
+ "https://github.com/processing/processing/issues/4997");
+ }
+ });
+ }
+ }
+ } catch (Exception e) {
+ Messages.loge("Problem checking NVIDIA driver", e);
+ }
+ }
+ }).start();
+ }
}
- static protected boolean isCommandLine() {
- return commandLine;
- }
+ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
- static public void initPlatform() {
- try {
- Class> platformClass = Class.forName("processing.app.Platform"); //$NON-NLS-1$
- if (Base.isMacOS()) {
- platformClass = Class.forName("processing.app.platform.MacPlatform"); //$NON-NLS-1$
- } else if (Base.isWindows()) {
- platformClass = Class.forName("processing.app.platform.WindowsPlatform"); //$NON-NLS-1$
- } else if (Base.isLinux()) {
- platformClass = Class.forName("processing.app.platform.LinuxPlatform"); //$NON-NLS-1$
- }
- platform = (Platform) platformClass.newInstance();
- } catch (Exception e) {
- Base.showError("Problem Setting the Platform",
- "An unknown error occurred while trying to load\n" +
- "platform-specific code for your machine.", e);
- }
+ /**
+ * @return the current revision number, safe to be used for update checks
+ */
+ static public int getRevision() {
+ return REVISION;
}
- public static void initRequirements() {
- try {
- Class.forName("com.sun.jdi.VirtualMachine"); //$NON-NLS-1$
- } catch (ClassNotFoundException cnfe) {
- //String cp = System.getProperty("java.class.path").replace(File.pathSeparatorChar, '\n');
-// String cp = System.getProperty("sun.boot.class.path").replace(File.pathSeparatorChar, '\n');
-
- Base.openURL("http://wiki.processing.org/w/Supported_Platforms");
-// Base.showError("Please install JDK 1.6 or later",
-// "Processing requires a full JDK (not just a JRE)\n" +
-// "to run. Please install JDK 1.6 or later.\n" +
-// "More information can be found on the Wiki." +
-// "\n\nJAVA_HOME is currently\n" +
-// System.getProperty("java.home") + "\n" +
-// "And the CLASSPATH contains\n" + cp, cnfe);
- Base.showError("Missing required files",
- "Processing requires a JRE with tools.jar (or a\n" +
- "full JDK) installed in (or linked to) a folder\n" +
- "named “java” next to the Processing application.\n" +
- "More information can be found on the Wiki.", cnfe);
- }
+ /**
+ * @return something like 2.2.1 or 3.0b4 (or 0213 if it's not a release)
+ */
+ static public String getVersionName() {
+ return VERSION_NAME;
}
- private void buildCoreModes() {
- Mode javaMode =
- ModeContribution.load(this, getContentFile("modes/java"), //$NON-NLS-1$
- "processing.mode.java.JavaMode").getMode(); //$NON-NLS-1$
-
- // PDE X calls getModeList() while it's loading, so coreModes must be set
- coreModes = new Mode[] { javaMode };
-
- Mode pdexMode =
- ModeContribution.load(this, getContentFile("modes/ExperimentalMode"), //$NON-NLS-1$
- "processing.mode.experimental.ExperimentalMode").getMode(); //$NON-NLS-1$
- // Safe to remove the old Java mode here?
- //coreModes = new Mode[] { pdexMode };
- coreModes = new Mode[] { pdexMode, javaMode };
+ public static void setCommandLine() {
+ commandLine = true;
}
- /**
- * Instantiates and adds new contributed modes to the contribModes list.
- * Checks for duplicates so the same mode isn't instantiates twice. Does not
- * remove modes because modes can't be removed once they are instantiated.
- */
- void rebuildContribModes() {
- if (modeContribs == null) {
- modeContribs = new ArrayList();
- }
- ModeContribution.loadMissing(this);
-
-// ArrayList newContribs =
-// ModeContribution.loadAll(getSketchbookModesFolder());
-// for (ModeContribution contrib : newContribs) {
-// if (!contribModes.contains(contrib)) {
-// if (contrib.instantiateModeClass(this)) {
-// contribModes.add(contrib);
-// }
-// }
-// }
+ static public boolean isCommandLine() {
+ return commandLine;
}
- /**
- * Instantiates and adds new contributed modes to the contribModes list.
- * Checks for duplicates so the same mode isn't instantiates twice. Does not
- * remove modes because modes can't be removed once they are instantiated.
- */
- void rebuildContribExamples() {
- if (exampleContribs == null) {
- exampleContribs = new ArrayList();
- }
- ExamplesPackageContribution.loadMissing(this);
- }
+ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
public Base(String[] args) throws Exception {
-// // Get the sketchbook path, and make sure it's set properly
-// determineSketchbookFolder();
-
- // Delete all modes and tools that have been flagged for deletion before
- // they are initialized by an editor.
-// ArrayList contribs = new ArrayList();
-// contribs.addAll(ModeContribution.list(getSketchbookModesFolder()));
-// contribs.addAll(ToolContribution.list(getSketchbookToolsFolder(), false));
-// for (InstalledContribution contrib : contribs) {
-// if (ContributionManager.isDeletionFlagSet(contrib)) {
-// removeDir(contrib.getFolder());
-// }
-// }
- ContributionManager.cleanup(this);
+ ContributionManager.init(this);
+
buildCoreModes();
rebuildContribModes();
-
rebuildContribExamples();
// Needs to happen after the sketchbook folder has been located.
// Also relies on the modes to be loaded so it knows what can be
// marked as an example.
- recent = new Recent(this);
+// recent = new Recent(this);
+ Recent.init(this);
String lastModeIdentifier = Preferences.get("mode.last"); //$NON-NLS-1$
if (lastModeIdentifier == null) {
nextMode = getDefaultMode();
- log("Nothing set for last.sketch.mode, using default."); //$NON-NLS-1$
+ Messages.log("Nothing set for last.sketch.mode, using default."); //$NON-NLS-1$
} else {
for (Mode m : getModeList()) {
if (m.getIdentifier().equals(lastModeIdentifier)) {
- logf("Setting next mode to %s.", lastModeIdentifier); //$NON-NLS-1$
+ Messages.logf("Setting next mode to %s.", lastModeIdentifier); //$NON-NLS-1$
nextMode = m;
}
}
if (nextMode == null) {
nextMode = getDefaultMode();
- logf("Could not find mode %s, using default.", lastModeIdentifier); //$NON-NLS-1$
+ Messages.logf("Could not find mode %s, using default.", lastModeIdentifier); //$NON-NLS-1$
}
}
- libraryManagerFrame =
- new ContributionManagerDialog(ContributionType.LIBRARY);
- toolManagerFrame =
- new ContributionManagerDialog(ContributionType.TOOL);
- modeManagerFrame =
- new ContributionManagerDialog(ContributionType.MODE);
- exampleManagerFrame =
- new ContributionManagerDialog(ContributionType.EXAMPLES_PACKAGE);
- updateManagerFrame =
- new ContributionManagerDialog(null);
+ //contributionManagerFrame = new ContributionManagerDialog();
// Make sure ThinkDifferent has library examples too
nextMode.rebuildLibraryList();
// Put this after loading the examples, so that building the default file
// menu works on Mac OS X (since it needs examplesFolder to be set).
- platform.init(this);
+ Platform.initBase(this);
// toolsFolder = getContentFile("tools");
@@ -399,15 +397,18 @@ public Base(String[] args) throws Exception {
// Check if any files were passed in on the command line
for (int i = 0; i < args.length; i++) {
+ Messages.logf("Parsing command line... args[%d] = '%s'", i, args[i]);
+
String path = args[i];
// Fix a problem with systems that use a non-ASCII languages. Paths are
// being passed in with 8.3 syntax, which makes the sketch loader code
// unhappy, since the sketch folder naming doesn't match up correctly.
// http://dev.processing.org/bugs/show_bug.cgi?id=1089
- if (isWindows()) {
+ if (Platform.isWindows()) {
try {
File file = new File(args[i]);
path = file.getCanonicalPath();
+ Messages.logf("Changing %s to canonical %s", i, args[i], path);
} catch (IOException e) {
e.printStackTrace();
}
@@ -419,97 +420,173 @@ public Base(String[] args) throws Exception {
// Create a new empty window (will be replaced with any files to be opened)
if (!opened) {
-// System.out.println("opening a new window");
+ Messages.log("Calling handleNew() to open a new window");
handleNew();
-// } else {
-// System.out.println("something else was opened");
+ } else {
+ Messages.log("No handleNew(), something passed on the command line");
}
// check for updates
- if (Preferences.getBoolean("update.check")) { //$NON-NLS-1$
- new UpdateCheck(this);
- }
+ new UpdateCheck(this);
+
+ ContributionListing cl = ContributionListing.getInstance();
+ cl.downloadAvailableList(this, new ContribProgressMonitor() { });
}
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
- /** Returns the front most, active editor window. */
- public Editor getActiveEditor() {
- return activeEditor;
- }
+ void buildCoreModes() {
+ Mode javaMode =
+ ModeContribution.load(this, Platform.getContentFile("modes/java"),
+ getDefaultModeIdentifier()).getMode();
+ // PDE X calls getModeList() while it's loading, so coreModes must be set
+ coreModes = new Mode[] { javaMode };
- /** Get the list of currently active editor windows. */
- public List getEditors() {
- return editors;
+ /*
+ Mode pdexMode =
+ ModeContribution.load(this, getContentFile("modes/ExperimentalMode"), //$NON-NLS-1$
+ "processing.mode.experimental.ExperimentalMode").getMode(); //$NON-NLS-1$
+
+ // Safe to remove the old Java mode here?
+ //coreModes = new Mode[] { pdexMode };
+ coreModes = new Mode[] { pdexMode, javaMode };
+ */
}
/**
- * The call has already checked to make sure this sketch is not modified,
- * now change the mode.
+ * Instantiates and adds new contributed modes to the contribModes list.
+ * Checks for duplicates so the same mode isn't instantiates twice. Does not
+ * remove modes because modes can't be removed once they are instantiated.
*/
- protected void changeMode(Mode mode) {
- if (activeEditor.getMode() != mode) {
- Sketch sketch = activeEditor.getSketch();
- nextMode = mode;
-
- if (sketch.isUntitled()) {
- // If no changes have been made, just close and start fresh.
- // (Otherwise the editor would lose its 'untitled' status.)
- handleClose(activeEditor, true);
- handleNew();
-
- } else {
- // If the current editor contains file extensions that the new mode can handle, then
- // write a sketch.properties file with the new mode specified, and reopen.
- boolean newModeCanHandleCurrentSource = true;
- for (final SketchCode code: sketch.getCode()) {
- if (!mode.validExtension(code.getExtension())) {
- newModeCanHandleCurrentSource = false;
- break;
+ void rebuildContribModes() {
+ if (modeContribs == null) {
+ modeContribs = new ArrayList<>();
+ }
+ File modesFolder = getSketchbookModesFolder();
+ List contribModes = getModeContribs();
+
+ Map known = new HashMap<>();
+ for (ModeContribution contrib : contribModes) {
+ known.put(contrib.getFolder(), contrib);
+ }
+ File[] potential = ContributionType.MODE.listCandidates(modesFolder);
+ // If modesFolder does not exist or is inaccessible (folks might like to
+ // mess with folders then report it as a bug) 'potential' will be null.
+ if (potential != null) {
+ for (File folder : potential) {
+ if (!known.containsKey(folder)) {
+ try {
+ contribModes.add(new ModeContribution(this, folder, null));
+ } catch (NoSuchMethodError nsme) {
+ System.err.println(folder.getName() + " is not compatible with this version of Processing");
+ if (DEBUG) nsme.printStackTrace();
+ } catch (NoClassDefFoundError ncdfe) {
+ System.err.println(folder.getName() + " is not compatible with this version of Processing");
+ if (DEBUG) ncdfe.printStackTrace();
+ } catch (InvocationTargetException ite) {
+ System.err.println(folder.getName() + " could not be loaded and may not compatible with this version of Processing");
+ if (DEBUG) ite.printStackTrace();
+ } catch (IgnorableException ig) {
+ Messages.log(ig.getMessage());
+ if (DEBUG) ig.printStackTrace();
+ } catch (Throwable e) {
+ System.err.println("Could not load Mode from " + folder);
+ e.printStackTrace();
}
+ } else {
+ known.remove(folder); // remove this item as already been seen
}
- if (newModeCanHandleCurrentSource) {
- final File props = new File(sketch.getCodeFolder(), "sketch.properties");
- saveModeSettings(props, nextMode);
- handleClose(activeEditor, true);
- handleOpen(sketch.getMainFilePath());
- }
+ }
+ }
+
+ // This allows you to build and test your Mode code from Eclipse.
+ // -Dusemode=com.foo.FrobMode:/path/to/FrobMode
+ final String useMode = System.getProperty("usemode");
+ if (useMode != null) {
+ final String[] modeInfo = useMode.split(":", 2);
+ final String modeClass = modeInfo[0];
+ final String modeResourcePath = modeInfo[1];
+ System.out.println("Attempting to load " + modeClass + " with resources at " + modeResourcePath);
+ ModeContribution mc = ModeContribution.load(this, new File(modeResourcePath), modeClass);
+ contribModes.add(mc);
+ File key = getFileForContrib(mc, known);
+ if (key != null) {
+ known.remove(key);
+ }
+ }
+ if (known.size() != 0) {
+ for (ModeContribution mc : known.values()) {
+ System.out.println("Extraneous Mode entry: " + mc.getName());
}
}
}
- public ArrayList getModeContribs() {
- return modeContribs;
+ static private File getFileForContrib(ModeContribution contrib,
+ Map known) {
+ for (Entry entry : known.entrySet()) {
+ if (entry.getValue() == contrib) {
+ return entry.getKey();
+ }
+ }
+ return null;
}
- public ArrayList getModeList() {
- ArrayList allModes = new ArrayList();
- allModes.addAll(Arrays.asList(coreModes));
- if (modeContribs != null) {
- for (ModeContribution contrib : modeContribs) {
- allModes.add(contrib.getMode());
- }
+ /**
+ * Instantiates and adds new contributed modes to the contribModes list.
+ * Checks for duplicates so the same mode isn't instantiates twice. Does not
+ * remove modes because modes can't be removed once they are instantiated.
+ */
+ void rebuildContribExamples() {
+ if (exampleContribs == null) {
+ exampleContribs = new ArrayList<>();
}
- return allModes;
+ ExamplesContribution.loadMissing(this);
}
- public ArrayList getExampleContribs() {
- return exampleContribs;
+ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+
+
+ /**
+ * Tools require an 'Editor' object when they're instantiated, but the
+ * activeEditor will be null when the first Editor that opens is creating
+ * its Tools menu. This will temporarily set the activeEditor to the one
+ * that's opening so that we don't go all NPE on startup. If there's already
+ * an active editor, then this does nothing.
+ */
+ public void checkFirstEditor(Editor editor) {
+ if (activeEditor == null) {
+ activeEditor = editor;
+ }
+ }
+
+
+ /** Returns the front most, active editor window. */
+ public Editor getActiveEditor() {
+ return activeEditor;
}
- // Because of variations in native windowing systems, no guarantees about
- // changes to the focused and active Windows can be made. Developers must
- // never assume that this Window is the focused or active Window until this
- // Window receives a WINDOW_GAINED_FOCUS or WINDOW_ACTIVATED event.
- protected void handleActivated(Editor whichEditor) {
+ /** Get the list of currently active editor windows. */
+ public List getEditors() {
+ return editors;
+ }
+
+
+ /**
+ * Called when a window is activated. Because of variations in native
+ * windowing systems, no guarantees about changes to the focused and active
+ * Windows can be made. Never assume that this Window is the focused or
+ * active Window until this Window actually receives a WINDOW_GAINED_FOCUS
+ * or WINDOW_ACTIVATED event.
+ */
+ public void handleActivated(Editor whichEditor) {
activeEditor = whichEditor;
// set the current window to be the console that's getting output
@@ -524,2468 +601,1451 @@ protected void handleActivated(Editor whichEditor) {
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
- boolean breakTime = false;
- String[] months = {
- "jan", "feb", "mar", "apr", "may", "jun",
- "jul", "aug", "sep", "oct", "nov", "dec"
- };
+ public void refreshContribs(ContributionType ct) {
+ if (ct == ContributionType.LIBRARY) {
+ for (Mode m : getModeList()) {
+ m.rebuildImportMenu();
+ }
+ } else if (ct == ContributionType.MODE) {
+ rebuildContribModes();
+ for (Editor editor : editors) {
+ editor.rebuildModePopup();
+ }
- /**
- * Create a new untitled document in a new sketch window.
- */
- public void handleNew() {
- try {
- File newbieDir = null;
- String newbieName = null;
+ } else if (ct == ContributionType.TOOL) {
+ rebuildToolList();
+ for (Editor editor : editors) {
+ populateToolsMenu(editor.getToolMenu());
+ }
- // In 0126, untitled sketches will begin in the temp folder,
- // and then moved to a new location because Save will default to Save As.
-// File sketchbookDir = getSketchbookFolder();
- File newbieParentDir = untitledFolder;
+ } else if (ct == ContributionType.EXAMPLES) {
+ rebuildContribExamples();
+ for (Mode m : getModeList()) {
+ m.rebuildExamplesFrame();
+ }
+ }
+ }
- String prefix = Preferences.get("editor.untitled.prefix");
- // Use a generic name like sketch_031008a, the date plus a char
- int index = 0;
- String format = Preferences.get("editor.untitled.suffix");
- String suffix = null;
- if (format == null) {
- Calendar cal = Calendar.getInstance();
- int day = cal.get(Calendar.DAY_OF_MONTH); // 1..31
- int month = cal.get(Calendar.MONTH); // 0..11
- suffix = months[month] + PApplet.nf(day, 2);
- } else {
- //SimpleDateFormat formatter = new SimpleDateFormat("yyMMdd");
- //SimpleDateFormat formatter = new SimpleDateFormat("MMMdd");
- //String purty = formatter.format(new Date()).toLowerCase();
- SimpleDateFormat formatter = new SimpleDateFormat(format);
- suffix = formatter.format(new Date());
- }
- do {
- if (index == 26) {
- // In 0159, avoid running past z by sending people outdoors.
- if (!breakTime) {
- Base.showWarning("Time for a Break",
- "You've reached the limit for auto naming of new sketches\n" +
- "for the day. How about going for a walk instead?", null);
- breakTime = true;
- } else {
- Base.showWarning("Sunshine",
- "No really, time for some fresh air for you.", null);
- }
- return;
- }
- newbieName = prefix + suffix + ((char) ('a' + index));
- // Also sanitize the name since it might do strange things on
- // non-English systems that don't use this sort of date format.
- // http://code.google.com/p/processing/issues/detail?id=283
- newbieName = Sketch.sanitizeName(newbieName);
- newbieDir = new File(newbieParentDir, newbieName);
- index++;
- // Make sure it's not in the temp folder *and* it's not in the sketchbook
- } while (newbieDir.exists() || new File(sketchbookFolder, newbieName).exists());
+ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
- // Make the directory for the new sketch
- newbieDir.mkdirs();
- // Make an empty pde file
- File newbieFile =
- new File(newbieDir, newbieName + "." + nextMode.getDefaultExtension()); //$NON-NLS-1$
- if (!newbieFile.createNewFile()) {
- throw new IOException(newbieFile + " already exists.");
- }
+ private int updatesAvailable = 0;
- // Create sketch properties file if it's not the default mode.
- if (!nextMode.equals(getDefaultMode())) {
- saveModeSettings(new File(newbieDir, "sketch.properties"), nextMode);
- }
-
- String path = newbieFile.getAbsolutePath();
- /*Editor editor =*/ handleOpen(path, true);
- } catch (IOException e) {
- Base.showWarning("That's new to me",
- "A strange and unexplainable error occurred\n" +
- "while trying to create a new sketch.", e);
+ public void setUpdatesAvailable(int n) {
+ updatesAvailable = n;
+ synchronized (editors) {
+ for (Editor e : editors) {
+ e.setUpdatesAvailable(n);
+ }
}
}
- // Create or modify a sketch.proprties file to specify the given Mode.
- private void saveModeSettings(final File sketchProps, final Mode mode) {
- try {
- final Settings settings = new Settings(sketchProps);
- settings.set("mode", mode.getTitle());
- settings.set("mode.id", mode.getIdentifier());
- settings.save();
- } catch (IOException e) {
- System.err.println("While creating " + sketchProps + ": " + e.getMessage());
- }
+
+ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+
+
+ List internalTools;
+ List coreTools;
+ List contribTools;
+
+
+ public List getCoreTools() {
+ return coreTools;
}
- public Mode getDefaultMode() {
- return coreModes[0];
+ public List getToolContribs() {
+ return contribTools;
}
- /** Used by ThinkDifferent so that it can have a Sketchbook menu. */
- public Mode getNextMode() {
- return nextMode;
+ public void removeToolContrib(ToolContribution tc) {
+ contribTools.remove(tc);
}
- /**
- * Prompt for a sketch to open, and open it in a new window.
- */
- public void handleOpenPrompt() {
- final ArrayList extensions = new ArrayList();
- for (Mode mode : getModeList()) {
- extensions.add(mode.getDefaultExtension());
+ public void rebuildToolList() {
+ // Only do this once because the list of internal tools will never change
+ if (internalTools == null) {
+ internalTools = new ArrayList<>();
+
+ initInternalTool("processing.app.tools.CreateFont");
+ initInternalTool("processing.app.tools.ColorSelector");
+ initInternalTool("processing.app.tools.Archiver");
+
+ if (Platform.isMacOS()) {
+ initInternalTool("processing.app.tools.InstallCommander");
+ }
}
+ // No need to reload these either
+ if (coreTools == null) {
+ coreTools = ToolContribution.loadAll(Base.getToolsFolder());
+ for (Tool tool : coreTools) {
+ tool.init(this);
+ }
+ }
- final String prompt = Language.text("open");
+ // Rebuilt when new tools installed, etc
+ contribTools = ToolContribution.loadAll(Base.getSketchbookToolsFolder());
+ for (Tool tool : contribTools) {
+ try {
+ tool.init(this);
- // don't use native dialogs on Linux (or anyone else w/ override)
- if (Preferences.getBoolean("chooser.files.native")) { //$NON-NLS-1$
- // use the front-most window frame for placing file dialog
- FileDialog openDialog =
- new FileDialog(activeEditor, prompt, FileDialog.LOAD);
+ // With the exceptions, we can't call statusError because the window
+ // isn't completely set up yet. Also not gonna pop up a warning because
+ // people may still be running different versions of Processing.
- // Only show .pde files as eligible bachelors
- openDialog.setFilenameFilter(new FilenameFilter() {
- public boolean accept(File dir, String name) {
- // confirmed to be working properly [fry 110128]
- for (String ext : extensions) {
- if (name.toLowerCase().endsWith("." + ext)) { //$NON-NLS-1$
- return true;
- }
- }
- return false;
- }
- });
+ } catch (VerifyError ve) {
+ System.err.println("\"" + tool.getMenuTitle() + "\" is not " +
+ "compatible with this version of Processing");
- openDialog.setVisible(true);
+ } catch (NoSuchMethodError nsme) {
+ System.err.println("\"" + tool.getMenuTitle() + "\" is not " +
+ "compatible with this version of Processing");
+ System.err.println("The " + nsme.getMessage() + " method no longer exists.");
+ Messages.loge("Incompatible Tool found during tool.init()", nsme);
- String directory = openDialog.getDirectory();
- String filename = openDialog.getFile();
- if (filename != null) {
- File inputFile = new File(directory, filename);
- handleOpen(inputFile.getAbsolutePath());
- }
+ } catch (NoClassDefFoundError ncdfe) {
+ System.err.println("\"" + tool.getMenuTitle() + "\" is not " +
+ "compatible with this version of Processing");
+ System.err.println("The " + ncdfe.getMessage() + " class is no longer available.");
+ Messages.loge("Incompatible Tool found during tool.init()", ncdfe);
- } else {
- if (openChooser == null) {
- openChooser = new JFileChooser();
- }
- openChooser.setDialogTitle(prompt);
+ } catch (AbstractMethodError ame) {
+ System.err.println("\"" + tool.getMenuTitle() + "\" is not " +
+ "compatible with this version of Processing");
+// ame.printStackTrace();
- openChooser.setFileFilter(new javax.swing.filechooser.FileFilter() {
- public boolean accept(File file) {
- // JFileChooser requires you to explicitly say yes to directories
- // as well (unlike the AWT chooser). Useful, but... different.
- // http://code.google.com/p/processing/issues/detail?id=1151
- if (file.isDirectory()) {
- return true;
- }
- for (String ext : extensions) {
- if (file.getName().toLowerCase().endsWith("." + ext)) { //$NON-NLS-1$
- return true;
- }
- }
- return false;
- }
+ } catch (Error err) {
+ System.err.println("An error occurred inside \"" + tool.getMenuTitle() + "\"");
+ err.printStackTrace();
- public String getDescription() {
- return "Processing Sketch";
- }
- });
- if (openChooser.showOpenDialog(activeEditor) == JFileChooser.APPROVE_OPTION) {
- handleOpen(openChooser.getSelectedFile().getAbsolutePath());
+ } catch (Exception ex) {
+ System.err.println("An exception occurred inside \"" + tool.getMenuTitle() + "\"");
+ ex.printStackTrace();
}
}
}
- /**
- * Open a sketch from the path specified. Do not use for untitled sketches.
- */
- public Editor handleOpen(String path) {
- return handleOpen(path, false);
- }
+ protected void initInternalTool(String className) {
+ try {
+ Class> toolClass = Class.forName(className);
+ final Tool tool = (Tool)
+ toolClass.getDeclaredConstructor().newInstance();
+ tool.init(this);
+ internalTools.add(tool);
- /**
- * Open a sketch in a new window.
- * @param path Path to the pde file for the sketch in question
- * @return the Editor object, so that properties (like 'untitled')
- * can be set by the caller
- */
- public Editor handleOpen(String path, boolean untitled) {
- return handleOpen(path, untitled, new EditorState(editors));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
}
-// protected Editor handleOpen(String path, int[] location) {
-// protected Editor handleOpen(String path, Rectangle bounds, int divider) {
- protected Editor handleOpen(String path, boolean untitled, EditorState state) {
- try {
- // System.err.println("entering handleOpen " + path);
-
- final File file = new File(path);
- if (!file.exists()) {
- return null;
- }
-
- // Cycle through open windows to make sure that it's not already open.
- for (Editor editor : editors) {
- // User may have double-clicked any PDE in the sketch folder,
- // so we have to check each open tab (not just the main one).
- // https://github.com/processing/processing/issues/2506
- for (SketchCode tab : editor.getSketch().getCode()) {
- if (tab.getFile().equals(file)) {
- editor.toFront();
- // move back to the top of the recent list
- handleRecent(editor);
- return editor;
+ /*
+ Iterator editorIter = base.getEditors().iterator();
+ while (editorIter.hasNext()) {
+ Editor editor = editorIter.next();
+ List contribTools = editor.getToolContribs();
+ for (ToolContribution toolContrib : contribTools) {
+ if (toolContrib.getName().equals(this.name)) {
+ try {
+ ((URLClassLoader) toolContrib.loader).close();
+ editor.removeToolContrib(toolContrib);
+ break;
+ } catch (IOException e) {
+ e.printStackTrace();
}
}
}
+ */
- if (!Sketch.isSanitaryName(file.getName())) {
- Base.showWarning("You're tricky, but not tricky enough",
- file.getName() + " is not a valid name for a sketch.\n" +
- "Better to stick to ASCII, no spaces, and make sure\n" +
- "it doesn't start with a number.", null);
- return null;
- }
- if (!nextMode.canEdit(file)) {
- final Mode mode = selectMode(file);
- if (mode == null) {
- return null;
- }
- nextMode = mode;
+ public void clearToolMenus() {
+ for (Editor ed : editors) {
+ ed.clearToolMenu();
+ }
+ }
+
+
+ public void populateToolsMenu(JMenu toolsMenu) {
+ // If this is the first run, need to build out the lists
+ if (internalTools == null) {
+ rebuildToolList();
+ }
+// coreTools = ToolContribution.loadAll(Base.getToolsFolder());
+// contribTools = ToolContribution.loadAll(Base.getSketchbookToolsFolder());
+
+// Collections.sort(coreTools);
+// Collections.sort(contribTools);
+// Collections.sort(coreTools, new Comparator() {
+// @Override
+// public int compare(ToolContribution o1, ToolContribution o2) {
+// return o1.getMenuTitle().compareTo(o2.getMenuTitle());
+// }
+// });
+ toolsMenu.removeAll();
+ for (Tool tool : internalTools) {
+ toolsMenu.add(createToolItem(tool));
+ }
+ toolsMenu.addSeparator();
+
+ if (coreTools.size() > 0) {
+ for (Tool tool : coreTools) {
+ toolsMenu.add(createToolItem(tool));
}
+ toolsMenu.addSeparator();
+ }
-// Editor.State state = new Editor.State(editors);
- Editor editor = nextMode.createEditor(this, path, state);
- if (editor == null) {
- // if it's not mode[0] already, then don't go into an infinite loop
- // trying to recreate a window with the default mode.
- Mode defaultMode = getDefaultMode();
- if (nextMode == defaultMode) {
- Base.showError("Editor Problems",
- "An error occurred while trying to change modes.\n" +
- "We'll have to quit for now because it's an\n" +
- "unfortunate bit of indigestion.",
- null);
- } else {
- editor = defaultMode.createEditor(this, path, state);
- }
+ if (contribTools.size() > 0) {
+ for (Tool tool : contribTools) {
+ toolsMenu.add(createToolItem(tool));
}
+ toolsMenu.addSeparator();
+ }
- // Make sure that the sketch actually loaded
- Sketch sketch = editor.getSketch();
- if (sketch == null) {
- return null; // Just walk away quietly
+ JMenuItem item = new JMenuItem(Language.text("menu.tools.add_tool"));
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ ContributionManager.openTools();
}
+ });
+ toolsMenu.add(item);
+ }
- sketch.setUntitled(untitled);
- editors.add(editor);
- handleRecent(editor);
- // now that we're ready, show the window
- // (don't do earlier, cuz we might move it based on a window being closed)
- editor.setVisible(true);
+ /*
+ static public void addTools(JMenu menu, List tools) {
+ Map toolItems = new HashMap();
- return editor;
+ for (final Tool tool : tools) {
+ // If init() fails, the item won't be added to the menu
+ addToolItem(tool, toolItems);
+ }
- } catch (Throwable t) {
- showBadnessTrace("Terrible News",
- "A serious error occurred while " +
- "trying to create a new editor window.", t, false);
- nextMode = getDefaultMode();
- return null;
+ List toolList = new ArrayList(toolItems.keySet());
+ if (toolList.size() > 0) {
+ if (menu.getItemCount() != 0) {
+ menu.addSeparator();
+ }
+ Collections.sort(toolList);
+ for (String title : toolList) {
+ menu.add(toolItems.get(title));
+ }
}
}
+ */
- private static class ModeInfo {
- public final String title;
- public final String id;
+ JMenuItem createToolItem(final Tool tool) { //, Map toolItems) {
+ String title = tool.getMenuTitle();
+ final JMenuItem item = new JMenuItem(title);
+ item.addActionListener(new ActionListener() {
- public ModeInfo(String id, String title) {
- this.id = id;
- this.title = title;
- }
+ public void actionPerformed(ActionEvent e) {
+ try {
+ tool.run();
+
+ } catch (NoSuchMethodError nsme) {
+ activeEditor.statusError("\"" + tool.getMenuTitle() + "\" is not" +
+ "compatible with this version of Processing");
+ //nsme.printStackTrace();
+ Messages.loge("Incompatible tool found during tool.run()", nsme);
+ item.setEnabled(false);
+
+ } catch (Exception ex) {
+ activeEditor.statusError("An error occurred inside \"" + tool.getMenuTitle() + "\"");
+ ex.printStackTrace();
+ item.setEnabled(false);
+ }
+ }
+ });
+ //toolItems.put(title, item);
+ return item;
}
- private static ModeInfo modeInfoFor(final File sketch) {
- final File sketchFolder = sketch.getParentFile();
- final File sketchProps = new File(sketchFolder, "sketch.properties");
- if (!sketchProps.exists()) {
- return null;
- }
- try {
- final Settings settings = new Settings(sketchProps);
- final String title = settings.get("mode");
- final String id = settings.get("mode.id");
- if (title == null || id == null) {
- return null;
- }
- return new ModeInfo(id, title);
- } catch (IOException e) {
- System.err.println("While trying to read " + sketchProps + ": "
- + e.getMessage());
- }
- return null;
+ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+
+
+ public List getModeContribs() {
+ return modeContribs;
}
- private Mode promptForMode(final File sketch, final ModeInfo preferredMode) {
- final String extension =
- sketch.getName().substring(sketch.getName().lastIndexOf('.') + 1);
- final List possibleModes = new ArrayList();
- for (final Mode mode : getModeList()) {
- if (mode.canEdit(sketch)) {
- possibleModes.add(mode);
- }
- }
- if (possibleModes.size() == 1 &&
- possibleModes.get(0).getIdentifier()
- .equals(JavaMode.class.getCanonicalName())) {
- // If default mode can open it, then do so without prompting.
- return possibleModes.get(0);
- }
- if (possibleModes.size() == 0) {
- if (preferredMode == null) {
- Base.showWarning("Modeless Dialog",
- "I don't know how to open a sketch with the \""
- + extension
- + "\"\nfile extension. You'll have to install a different"
- + "\nProcessing mode for that.");
- } else {
- Base.showWarning("Modeless Dialog", "You'll have to install "
- + preferredMode.title + " Mode " + "\nin order to open that sketch.");
+ public List getModeList() {
+ List allModes = new ArrayList<>();
+ allModes.addAll(Arrays.asList(coreModes));
+ if (modeContribs != null) {
+ for (ModeContribution contrib : modeContribs) {
+ allModes.add(contrib.getMode());
}
- return null;
}
- final Mode[] modes = possibleModes.toArray(new Mode[possibleModes.size()]);
- final String message = preferredMode == null ?
- (nextMode.getTitle() + " Mode can't open ." + extension + " files, " +
- "but you have one or more modes\ninstalled that can. " +
- "Would you like to try one?") :
- ("That's a " + preferredMode.title + " Mode sketch, " +
- "but you don't have " + preferredMode.title + " installed.\n" +
- "Would you like to try a different mode for opening a " +
- "." + extension + " sketch?");
- return (Mode) JOptionPane.showInputDialog(null, message, "Choose Wisely",
- JOptionPane.QUESTION_MESSAGE,
- null, modes, modes[0]);
+ return allModes;
}
- private Mode selectMode(final File sketch) {
- final ModeInfo modeInfo = modeInfoFor(sketch);
- final Mode specifiedMode = modeInfo == null ? null : findMode(modeInfo.id);
- if (specifiedMode != null) {
- return specifiedMode;
+ public List getExampleContribs() {
+ return exampleContribs;
+ }
+
+
+ private List getInstalledContribs() {
+ List contributions = new ArrayList<>();
+
+ List modeContribs = getModeContribs();
+ contributions.addAll(modeContribs);
+
+ for (ModeContribution modeContrib : modeContribs) {
+ Mode mode = modeContrib.getMode();
+ contributions.addAll(new ArrayList<>(mode.contribLibraries));
}
- return promptForMode(sketch, modeInfo);
+
+ // TODO this duplicates code in Editor, but it's not editor-specific
+// List toolContribs =
+// ToolContribution.loadAll(Base.getSketchbookToolsFolder());
+// contributions.addAll(toolContribs);
+ contributions.addAll(ToolContribution.loadAll(getSketchbookToolsFolder()));
+
+ contributions.addAll(getExampleContribs());
+ return contributions;
}
- protected Mode findMode(String id) {
- for (Mode mode : getModeList()) {
- if (mode.getIdentifier().equals(id)) {
- return mode;
- }
+ public byte[] getInstalledContribsInfo() {
+ List contribs = getInstalledContribs();
+ StringList entries = new StringList();
+ for (Contribution c : contribs) {
+ String entry = c.getTypeName() + "=" +
+ PApplet.urlEncode(String.format("name=%s\nurl=%s\nrevision=%d\nversion=%s",
+ c.getName(), c.getUrl(),
+ c.getVersion(), c.getBenignVersion()));
+ entries.append(entry);
}
- return null;
+ String joined =
+ "id=" + UpdateCheck.getUpdateID() + "&" + entries.join("&");
+// StringBuilder sb = new StringBuilder();
+// try {
+// // Truly ridiculous attempt to shove everything into a GET request.
+// // More likely to be seen as part of a grand plot.
+// ByteArrayOutputStream baos = new ByteArrayOutputStream();
+// GZIPOutputStream output = new GZIPOutputStream(baos);
+// PApplet.saveStream(output, new ByteArrayInputStream(joined.getBytes()));
+// output.close();
+// byte[] b = baos.toByteArray();
+// for (int i = 0; i < b.length; i++) {
+// sb.append(PApplet.hex(b[i], 2));
+// }
+// } catch (IOException e) {
+// e.printStackTrace();
+// }
+// return sb.toString();
+ return joined.getBytes();
}
+ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+
+
/**
- * Close a sketch as specified by its editor window.
- * @param editor Editor object of the sketch to be closed.
- * @param modeSwitch Whether this close is being done in the context of a
- * mode switch.
- * @return true if succeeded in closing, false if canceled.
- */
- public boolean handleClose(Editor editor, boolean modeSwitch) {
- // Check if modified
-// boolean immediate = editors.size() == 1;
- if (!editor.checkModified()) {
- return false;
- }
-
- // Close the running window, avoid window boogers with multiple sketches
- editor.internalCloseRunner();
-
-// System.out.println("editors size is " + editors.size());
- if (editors.size() == 1) {
- // For 0158, when closing the last window /and/ it was already an
- // untitled sketch, just give up and let the user quit.
-// if (Preferences.getBoolean("sketchbook.closing_last_window_quits") ||
-// (editor.untitled && !editor.getSketch().isModified())) {
- if (Base.isMacOS()) {
- // If the central menubar isn't supported on this OS X JVM,
- // we have to do the old behavior. Yuck!
- if (defaultFileMenu == null) {
- Object[] options = { Language.text("prompt.ok"), Language.text("prompt.cancel") };
- String prompt =
- " " +
- " " +
- "Are you sure you want to Quit?" +
- "
Closing the last open sketch will quit Processing.";
-
- int result = JOptionPane.showOptionDialog(editor,
- prompt,
- "Quit",
- JOptionPane.YES_NO_OPTION,
- JOptionPane.QUESTION_MESSAGE,
- null,
- options,
- options[0]);
- if (result == JOptionPane.NO_OPTION ||
- result == JOptionPane.CLOSED_OPTION) {
- return false;
- }
- }
- }
-
- Preferences.unset("server.port"); //$NON-NLS-1$
- Preferences.unset("server.key"); //$NON-NLS-1$
-
- // This will store the sketch count as zero
- editors.remove(editor);
-// System.out.println("editors size now " + editors.size());
-// storeSketches();
-
- // Save out the current prefs state
- Preferences.save();
-
- if (defaultFileMenu == null) {
- if (modeSwitch) {
- // need to close this editor, ever so temporarily
- editor.setVisible(false);
- editor.dispose();
- activeEditor = null;
- editors.remove(editor);
- } else {
- // Since this wasn't an actual Quit event, call System.exit()
- System.exit(0);
- }
- } else { // on OS X, update the default file menu
- editor.setVisible(false);
- editor.dispose();
- defaultFileMenu.insert(getRecentMenu(), 2);
- activeEditor = null;
- editors.remove(editor);
- }
-
- } else {
- // More than one editor window open,
- // proceed with closing the current window.
- editor.setVisible(false);
- editor.dispose();
- editors.remove(editor);
- }
- return true;
- }
-
-
- /**
- * Handler for File → Quit.
- * @return false if canceled, true otherwise.
- */
- public boolean handleQuit() {
- // If quit is canceled, this will be replaced anyway
- // by a later handleQuit() that is not canceled.
-// storeSketches();
-
- if (handleQuitEach()) {
- // make sure running sketches close before quitting
- for (Editor editor : editors) {
- editor.internalCloseRunner();
- }
- // Save out the current prefs state
- Preferences.save();
-
- if (!Base.isMacOS()) {
- // If this was fired from the menu or an AppleEvent (the Finder),
- // then Mac OS X will send the terminate signal itself.
- System.exit(0);
- }
- return true;
- }
- return false;
- }
-
-
- /**
- * Attempt to close each open sketch in preparation for quitting.
- * @return false if canceled along the way
- */
- protected boolean handleQuitEach() {
-// int index = 0;
- for (Editor editor : editors) {
-// if (editor.checkModified()) {
-// // Update to the new/final sketch path for this fella
-// storeSketchPath(editor, index);
-// index++;
-//
-// } else {
-// return false;
-// }
- if (!editor.checkModified()) {
- return false;
- }
- }
- return true;
- }
-
-
- // .................................................................
-
-
- /**
- * Asynchronous version of menu rebuild to be used on save and rename
- * to prevent the interface from locking up until the menus are done.
- */
- protected void rebuildSketchbookMenusAsync() {
- //System.out.println("async enter");
- //new Exception().printStackTrace();
- EventQueue.invokeLater(new Runnable() {
- public void run() {
- rebuildSketchbookMenus();
- }
- });
- }
-
-
- public void thinkDifferentExamples() {
- nextMode.showExamplesFrame();
- }
-
-
- /**
- * Synchronous version of rebuild, used when the sketchbook folder has
- * changed, so that the libraries are properly re-scanned before those menus
- * (and the examples window) are rebuilt.
- */
- protected void rebuildSketchbookMenus() {
- // rebuildSketchbookMenu(); // no need to rebuild sketchbook post 3.0
- for (Mode mode : getModeList()) {
- //mode.rebuildLibraryList();
- mode.rebuildImportMenu(); // calls rebuildLibraryList
- mode.rebuildToolbarMenu();
- mode.resetExamples();
- }
- }
-
-
- protected void rebuildSketchbookMenu() {
-// System.err.println("sketchbook: " + sketchbookFolder);
- sketchbookMenu.removeAll();
- populateSketchbookMenu(sketchbookMenu);
-// boolean found = false;
-// try {
-// found = addSketches(sketchbookMenu, sketchbookFolder, false);
-// } catch (IOException e) {
-// Base.showWarning("Sketchbook Menu Error",
-// "An error occurred while trying to list the sketchbook.", e);
-// }
-// if (!found) {
-// JMenuItem empty = new JMenuItem("(empty)");
-// empty.setEnabled(false);
-// sketchbookMenu.add(empty);
-// }
- }
-
-
- public void populateSketchbookMenu(JMenu menu) {
- boolean found = false;
- try {
- found = addSketches(menu, sketchbookFolder, false);
- } catch (IOException e) {
- Base.showWarning("Sketchbook Menu Error",
- "An error occurred while trying to list the sketchbook.", e);
- }
- if (!found) {
- JMenuItem empty = new JMenuItem(Language.text("menu.file.sketchbook.empty"));
- empty.setEnabled(false);
- menu.add(empty);
- }
- }
-
-
-// public JMenu getSketchbookMenu() {
-// if (sketchbookMenu == null) {
-// sketchbookMenu = new JMenu(Language.text("menu.file.sketchbook"));
-// rebuildSketchbookMenu();
-// }
-// return sketchbookMenu;
-// }
-
-
-// public JMenu getRecentMenu() {
-// if (recentMenu == null) {
-// recentMenu = recent.createMenu();
-// } else {
-// recent.updateMenu(recentMenu);
-// }
-// return recentMenu;
-// }
-
-
- public JMenu getRecentMenu() {
- return recent.getMenu();
- }
-
-
- public JMenu getToolbarRecentMenu() {
- return recent.getToolbarMenu();
- }
-
-
- public void handleRecent(Editor editor) {
- recent.handle(editor);
- }
-
-
- /**
- * Called before a sketch is renamed so that its old name is
- * no longer in the menu.
- */
- public void removeRecent(Editor editor) {
- recent.remove(editor);
- }
-
-
- /**
- * Scan a folder recursively, and add any sketches found to the menu
- * specified. Set the openReplaces parameter to true when opening the sketch
- * should replace the sketch in the current window, or false when the
- * sketch should open in a new window.
- */
- protected boolean addSketches(JMenu menu, File folder,
- final boolean replaceExisting) throws IOException {
- // skip .DS_Store files, etc (this shouldn't actually be necessary)
- if (!folder.isDirectory()) {
- return false;
- }
-
- if (folder.getName().equals("libraries")) {
- return false; // let's not go there
- }
-
- String[] list = folder.list();
- // If a bad folder or unreadable or whatever, this will come back null
- if (list == null) {
- return false;
- }
-
- // Alphabetize the list, since it's not always alpha order
- Arrays.sort(list, String.CASE_INSENSITIVE_ORDER);
-
- ActionListener listener = new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- String path = e.getActionCommand();
- if (new File(path).exists()) {
- boolean replace = replaceExisting;
- if ((e.getModifiers() & ActionEvent.SHIFT_MASK) != 0) {
- replace = !replace;
- }
-// if (replace) {
-// handleOpenReplace(path);
-// } else {
- handleOpen(path);
-// }
- } else {
- showWarning("Sketch Disappeared",
- "The selected sketch no longer exists.\n" +
- "You may need to restart Processing to update\n" +
- "the sketchbook menu.", null);
- }
- }
- };
- // offers no speed improvement
- //menu.addActionListener(listener);
-
- boolean found = false;
-
-// for (int i = 0; i < list.length; i++) {
-// if ((list[i].charAt(0) == '.') ||
-// list[i].equals("CVS")) continue;
- for (String name : list) {
- if (name.charAt(0) == '.') {
- continue;
- }
-
- File subfolder = new File(folder, name);
- if (subfolder.isDirectory()) {
- File entry = checkSketchFolder(subfolder, name);
- if (entry != null) {
-
-// File entry = new File(subfolder, list[i] + getExtension());
-// // if a .pde file of the same prefix as the folder exists..
-// if (entry.exists()) {
-// //String sanityCheck = sanitizedName(list[i]);
-// //if (!sanityCheck.equals(list[i])) {
-// if (!Sketch.isSanitaryName(list[i])) {
-// if (!builtOnce) {
-// String complaining =
-// "The sketch \"" + list[i] + "\" cannot be used.\n" +
-// "Sketch names must contain only basic letters and numbers\n" +
-// "(ASCII-only with no spaces, " +
-// "and it cannot start with a number).\n" +
-// "To get rid of this message, remove the sketch from\n" +
-// entry.getAbsolutePath();
-// Base.showMessage("Ignoring sketch with bad name", complaining);
-// }
-// continue;
-// }
-
- JMenuItem item = new JMenuItem(name);
- item.addActionListener(listener);
- item.setActionCommand(entry.getAbsolutePath());
- menu.add(item);
- found = true;
-
- } else {
- // not a sketch folder, but maybe a subfolder containing sketches
- JMenu submenu = new JMenu(name);
- // needs to be separate var otherwise would set ifound to false
- boolean anything = addSketches(submenu, subfolder, replaceExisting);
- if (anything && !name.equals("old")) { //Don't add old contributions
- menu.add(submenu);
- found = true;
- }
- }
- }
- }
- return found;
- }
-
-
- protected boolean addSketches(DefaultMutableTreeNode node, File folder) throws IOException {
- // skip .DS_Store files, etc (this shouldn't actually be necessary)
- if (!folder.isDirectory()) {
- return false;
- }
-
- if (folder.getName().equals("libraries")) {
- return false; // let's not go there
- }
-
- String[] list = folder.list();
- // If a bad folder or unreadable or whatever, this will come back null
- if (list == null) {
- return false;
- }
-
- // Alphabetize the list, since it's not always alpha order
- Arrays.sort(list, String.CASE_INSENSITIVE_ORDER);
-
-// ActionListener listener = new ActionListener() {
-// public void actionPerformed(ActionEvent e) {
-// String path = e.getActionCommand();
-// if (new File(path).exists()) {
-// handleOpen(path);
-// } else {
-// showWarning("Sketch Disappeared",
-// "The selected sketch no longer exists.\n" +
-// "You may need to restart Processing to update\n" +
-// "the sketchbook menu.", null);
-// }
-// }
-// };
- // offers no speed improvement
- //menu.addActionListener(listener);
-
- boolean found = false;
-
- for (String name : list) {
- if (name.charAt(0) == '.') {
- continue;
- }
-
-// JTree tree = null;
-// TreePath[] a = tree.getSelectionPaths();
-// for (TreePath path : a) {
-// Object[] o = path.getPath();
-// }
-
- File subfolder = new File(folder, name);
- if (subfolder.isDirectory()) {
- File entry = checkSketchFolder(subfolder, name);
- if (entry != null) {
-// DefaultMutableTreeNode item = new DefaultMutableTreeNode(name);
- DefaultMutableTreeNode item =
- new DefaultMutableTreeNode(new SketchReference(name, entry));
-// item.addActionListener(listener);
-// item.setActionCommand(entry.getAbsolutePath());
-// menu.add(item);
- node.add(item);
- found = true;
-
- } else {
- // not a sketch folder, but maybe a subfolder containing sketches
-// JMenu submenu = new JMenu(name);
- DefaultMutableTreeNode subnode = new DefaultMutableTreeNode(name);
- // needs to be separate var otherwise would set ifound to false
- boolean anything = addSketches(subnode, subfolder);
- if (anything) {
- node.add(subnode);
- found = true;
- }
- }
- }
- }
- return found;
- }
-
-
- /**
- * Check through the various modes and see if this is a legit sketch.
- * Because the default mode will be the first in the list, this will always
- * prefer that one over the others.
- */
- File checkSketchFolder(File subfolder, String item) {
- for (Mode mode : getModeList()) {
- File entry = new File(subfolder, item + "." + mode.getDefaultExtension()); //$NON-NLS-1$
- // if a .pde file of the same prefix as the folder exists..
- if (entry.exists()) {
- return entry;
- }
- // for the new releases, don't bother lecturing.. just ignore the sketch
- /*
- if (!Sketch.isSanitaryName(list[i])) {
- if (!builtOnce) {
- String complaining =
- "The sketch \"" + list[i] + "\" cannot be used.\n" +
- "Sketch names must contain only basic letters and numbers\n" +
- "(ASCII-only with no spaces, " +
- "and it cannot start with a number).\n" +
- "To get rid of this message, remove the sketch from\n" +
- entry.getAbsolutePath();
- Base.showMessage("Ignoring sketch with bad name", complaining);
- }
- continue;
- }
- */
- }
- return null;
- }
-
-
- // .................................................................
-
-
-// /**
-// * Show the About box.
-// */
-// static public void handleAbout() {
-// new About(activeEditor);
-// }
-
-
- /**
- * Show the Preferences window.
+ * Create or modify a sketch.proprties file to specify the given Mode.
*/
- public void handlePrefs() {
- if (preferencesFrame == null) {
- preferencesFrame = new PreferencesFrame(this);
+ private void saveModeSettings(final File sketchProps, final Mode mode) {
+ try {
+ final Settings settings = new Settings(sketchProps);
+ settings.set("mode", mode.getTitle());
+ settings.set("mode.id", mode.getIdentifier());
+ settings.save();
+ } catch (IOException e) {
+ System.err.println("While creating " + sketchProps + ": " + e.getMessage());
}
- preferencesFrame.showFrame();
- }
-
-
- /**
- * Show the library installer window.
- */
- public void handleOpenLibraryManager() {
- libraryManagerFrame.showFrame(activeEditor);
- }
-
-
- /**
- * Show the tool installer window.
- */
- public void handleOpenToolManager() {
- toolManagerFrame.showFrame(activeEditor);
- }
-
-
- /**
- * Show the mode installer window.
- */
- public void handleOpenModeManager() {
- modeManagerFrame.showFrame(activeEditor);
}
- /**
- * Show the examples installer window.
- */
- public void handleOpenExampleManager() {
- exampleManagerFrame.showFrame(activeEditor);
+ String getDefaultModeIdentifier() {
+ return "processing.mode.java.JavaMode";
}
- public void handleShowUpdates() {
- updateManagerFrame.showFrame(activeEditor);
+ public Mode getDefaultMode() {
+ return coreModes[0];
}
- // ...................................................................
-
-
- static public int getRevision() {
- return REVISION;
+ /** Used by ThinkDifferent so that it can have a Sketchbook menu. */
+ public Mode getNextMode() {
+ return nextMode;
}
/**
- * Return the version name, something like 1.5 or 2.0b8 or 0213 if it's not
- * a release version.
+ * The call has already checked to make sure this sketch is not modified,
+ * now change the mode.
+ * @return true if mode is changed.
*/
- static public String getVersionName() {
- return VERSION_NAME;
- }
-
-
- //...................................................................
-
-
- static public Platform getPlatform() {
- return platform;
- }
-
-
- static public String getPlatformName() {
- return PConstants.platformNames[PApplet.platform];
- }
-
+ public boolean changeMode(Mode mode) {
+ Mode oldMode = activeEditor.getMode();
+ if (oldMode != mode) {
+ Sketch sketch = activeEditor.getSketch();
+ nextMode = mode;
- // Because the Oracle JDK is 64-bit only, we lose this ability, feature,
- // edge case, headache.
-// /**
-// * Return whether sketches will run as 32- or 64-bits. On Linux and Windows,
-// * this is the bit depth of the machine, while on OS X it's determined by the
-// * setting from preferences, since both 32- and 64-bit are supported.
-// */
-// static public int getNativeBits() {
-// if (Base.isMacOS()) {
-// return Preferences.getInteger("run.options.bits"); //$NON-NLS-1$
-// }
-// return nativeBits;
-// }
+ if (sketch.isUntitled()) {
+ // The current sketch is empty, just close and start fresh.
+ // (Otherwise the editor would lose its 'untitled' status.)
+ handleClose(activeEditor, true);
+ handleNew();
- /**
- * Return whether sketches will run as 32- or 64-bits based
- * on the JVM that's in use.
- */
- static public int getNativeBits() {
- return nativeBits;
+ } else {
+ // If the current editor contains file extensions that the new mode can handle, then
+ // write a sketch.properties file with the new mode specified, and reopen.
+ boolean newModeCanHandleCurrentSource = true;
+ for (final SketchCode code : sketch.getCode()) {
+ if (!mode.validExtension(code.getExtension())) {
+ newModeCanHandleCurrentSource = false;
+ break;
+ }
+ }
+ if (!newModeCanHandleCurrentSource) {
+ return false;
+ } else {
+ final File props = new File(sketch.getCodeFolder(), "sketch.properties");
+ saveModeSettings(props, nextMode);
+ handleClose(activeEditor, true);
+ Editor editor = handleOpen(sketch.getMainFilePath());
+ if (editor == null) {
+ // the Mode change failed (probably code that's out of date)
+ // re-open the sketch using the mode we were in before
+ saveModeSettings(props, oldMode);
+ handleOpen(sketch.getMainFilePath());
+ return false;
+ }
+ }
+ }
+ }
+ return true;
}
- /*
- static public String getPlatformName() {
- String osname = System.getProperty("os.name");
-
- if (osname.indexOf("Mac") != -1) {
- return "macosx";
-
- } else if (osname.indexOf("Windows") != -1) {
- return "windows";
-
- } else if (osname.equals("Linux")) { // true for the ibm vm
- return "linux";
+ private static class ModeInfo {
+ public final String title;
+ public final String id;
- } else {
- return "other";
+ public ModeInfo(String id, String title) {
+ this.id = id;
+ this.title = title;
}
}
- */
- /**
- * Map a platform constant to its name.
- * @param which PConstants.WINDOWS, PConstants.MACOSX, PConstants.LINUX
- * @return one of "windows", "macosx", or "linux"
- */
- static public String getPlatformName(int which) {
- return platformNames.get(which);
+ private static ModeInfo modeInfoFor(final File sketch) {
+ final File sketchFolder = sketch.getParentFile();
+ final File sketchProps = new File(sketchFolder, "sketch.properties");
+ if (!sketchProps.exists()) {
+ return null;
+ }
+ try {
+ final Settings settings = new Settings(sketchProps);
+ final String title = settings.get("mode");
+ final String id = settings.get("mode.id");
+ if (title == null || id == null) {
+ return null;
+ }
+ return new ModeInfo(id, title);
+ } catch (IOException e) {
+ System.err.println("While trying to read " + sketchProps + ": "
+ + e.getMessage());
+ }
+ return null;
}
- static public int getPlatformIndex(String what) {
- Integer entry = platformIndices.get(what);
- return (entry == null) ? -1 : entry.intValue();
+ private Mode promptForMode(final File sketch, final ModeInfo preferredMode) {
+ final String extension =
+ sketch.getName().substring(sketch.getName().lastIndexOf('.') + 1);
+ final List possibleModes = new ArrayList<>();
+ for (final Mode mode : getModeList()) {
+ if (mode.canEdit(sketch)) {
+ possibleModes.add(mode);
+ }
+ }
+ if (possibleModes.size() == 1 &&
+ possibleModes.get(0).getIdentifier().equals(getDefaultModeIdentifier())) {
+ // If default mode can open it, then do so without prompting.
+ return possibleModes.get(0);
+ }
+ if (possibleModes.size() == 0) {
+ if (preferredMode == null) {
+ final String msg =
+ "I don't know how to open a sketch with the \"" + extension + "\"\n" +
+ "file extension. You'll have to install a different\n" +
+ "Mode for that.";
+ Messages.showWarning("Modeless Dialog", msg);
+ } else {
+ Messages.showWarning("Modeless Dialog",
+ "Install " + preferredMode.title + " Mode " +
+ "to open this sketch.");
+ }
+ return null;
+ }
+ final Mode[] modes = possibleModes.toArray(new Mode[possibleModes.size()]);
+ final String message = preferredMode == null ?
+ (nextMode.getTitle() + " Mode can't open ." + extension + " files, " +
+ "but you have one or more modes\ninstalled that can. " +
+ "Would you like to try one?") :
+ ("That's a " + preferredMode.title + " Mode sketch, " +
+ "but you don't have " + preferredMode.title + " installed.\n" +
+ "Would you like to try a different mode for opening a " +
+ "." + extension + " sketch?");
+ return (Mode) JOptionPane.showInputDialog(null, message, "Choose Wisely",
+ JOptionPane.QUESTION_MESSAGE,
+ null, modes, modes[0]);
}
- // These were changed to no longer rely on PApplet and PConstants because
- // of conflicts that could happen with older versions of core.jar, where
- // the MACOSX constant would instead read as the LINUX constant.
-
-
- /**
- * returns true if Processing is running on a Mac OS X machine.
- */
- static public boolean isMacOS() {
- //return PApplet.platform == PConstants.MACOSX;
- return System.getProperty("os.name").indexOf("Mac") != -1; //$NON-NLS-1$ //$NON-NLS-2$
+ private Mode selectMode(final File sketch) {
+ final ModeInfo modeInfo = modeInfoFor(sketch);
+ final Mode specifiedMode = modeInfo == null ? null : findMode(modeInfo.id);
+ if (specifiedMode != null) {
+ return specifiedMode;
+ }
+ return promptForMode(sketch, modeInfo);
}
- static private Boolean usableOracleJava;
-
- // Make sure this is Oracle Java 7u40 or later. This is temporary.
- static public boolean isUsableOracleJava() {
- if (usableOracleJava == null) {
- usableOracleJava = false;
-
- if (Base.isMacOS() &&
- System.getProperty("java.vendor").contains("Oracle")) {
- String version = System.getProperty("java.version"); // 1.7.0_40
- String[] m = PApplet.match(version, "1.(\\d).*_(\\d+)");
-
- if (m != null &&
- PApplet.parseInt(m[1]) >= 7 &&
- PApplet.parseInt(m[2]) >= 40) {
- usableOracleJava = true;
- }
+ protected Mode findMode(String id) {
+ for (Mode mode : getModeList()) {
+ if (mode.getIdentifier().equals(id)) {
+ return mode;
}
}
- return usableOracleJava;
- }
-
-
- /**
- * returns true if running on windows.
- */
- static public boolean isWindows() {
- //return PApplet.platform == PConstants.WINDOWS;
- return System.getProperty("os.name").indexOf("Windows") != -1; //$NON-NLS-1$ //$NON-NLS-2$
+ return null;
}
- /**
- * true if running on linux.
- */
- static public boolean isLinux() {
- //return PApplet.platform == PConstants.LINUX;
- return System.getProperty("os.name").indexOf("Linux") != -1; //$NON-NLS-1$ //$NON-NLS-2$
- }
+ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+ boolean breakTime = false;
+ String[] months = {
+ "jan", "feb", "mar", "apr", "may", "jun",
+ "jul", "aug", "sep", "oct", "nov", "dec"
+ };
/**
- * Get the directory that can store settings. (Library on OS X, App Data or
- * something similar on Windows, a dot folder on Linux.) Removed this as a
- * preference for 3.0a3 because we need this to be stable.
+ * Create a new untitled document in a new sketch window.
*/
- static public File getSettingsFolder() {
- File settingsFolder = null;
-
-// String preferencesPath = Preferences.get("settings.path"); //$NON-NLS-1$
-// if (preferencesPath != null) {
-// settingsFolder = new File(preferencesPath);
-//
-// } else {
+ public void handleNew() {
try {
- settingsFolder = platform.getSettingsFolder();
- } catch (Exception e) {
- showError("Problem getting the settings folder",
- "Error getting the Processing the settings folder.", e);
- }
-// }
+ File newbieDir = null;
+ String newbieName = null;
- // create the folder if it doesn't exist already
- if (!settingsFolder.exists()) {
- if (!settingsFolder.mkdirs()) {
- showError("Settings issues",
- "Processing cannot run because it could not\n" +
- "create a folder to store your settings.", null);
- }
- }
- return settingsFolder;
- }
+ // In 0126, untitled sketches will begin in the temp folder,
+ // and then moved to a new location because Save will default to Save As.
+// File sketchbookDir = getSketchbookFolder();
+ File newbieParentDir = untitledFolder;
+
+ String prefix = Preferences.get("editor.untitled.prefix");
+ // Use a generic name like sketch_031008a, the date plus a char
+ int index = 0;
+ String format = Preferences.get("editor.untitled.suffix");
+ String suffix = null;
+ if (format == null) {
+ Calendar cal = Calendar.getInstance();
+ int day = cal.get(Calendar.DAY_OF_MONTH); // 1..31
+ int month = cal.get(Calendar.MONTH); // 0..11
+ suffix = months[month] + PApplet.nf(day, 2);
+ } else {
+ //SimpleDateFormat formatter = new SimpleDateFormat("yyMMdd");
+ //SimpleDateFormat formatter = new SimpleDateFormat("MMMdd");
+ //String purty = formatter.format(new Date()).toLowerCase();
+ SimpleDateFormat formatter = new SimpleDateFormat(format);
+ suffix = formatter.format(new Date());
+ }
+ do {
+ if (index == 26) {
+ // In 0159, avoid running past z by sending people outdoors.
+ if (!breakTime) {
+ Messages.showWarning("Time for a Break",
+ "You've reached the limit for auto naming of new sketches\n" +
+ "for the day. How about going for a walk instead?", null);
+ breakTime = true;
+ } else {
+ Messages.showWarning("Sunshine",
+ "No really, time for some fresh air for you.", null);
+ }
+ return;
+ }
+ newbieName = prefix + suffix + ((char) ('a' + index));
+ // Also sanitize the name since it might do strange things on
+ // non-English systems that don't use this sort of date format.
+ // http://code.google.com/p/processing/issues/detail?id=283
+ newbieName = Sketch.sanitizeName(newbieName);
+ newbieDir = new File(newbieParentDir, newbieName);
+ index++;
+ // Make sure it's not in the temp folder *and* it's not in the sketchbook
+ } while (newbieDir.exists() || new File(sketchbookFolder, newbieName).exists());
- /**
- * Convenience method to get a File object for the specified filename inside
- * the settings folder. Used to get preferences and recent sketch files.
- * @param filename A file inside the settings folder.
- * @return filename wrapped as a File object inside the settings folder
- */
- static public File getSettingsFile(String filename) {
- return new File(getSettingsFolder(), filename);
- }
+ // Make the directory for the new sketch
+ newbieDir.mkdirs();
+ // Add any template files from the Mode itself
+ File newbieFile = nextMode.addTemplateFiles(newbieDir, newbieName);
- /*
- static public File getBuildFolder() {
- if (buildFolder == null) {
- String buildPath = Preferences.get("build.path");
- if (buildPath != null) {
- buildFolder = new File(buildPath);
+ /*
+ // Make an empty pde file
+ File newbieFile =
+ new File(newbieDir, newbieName + "." + nextMode.getDefaultExtension()); //$NON-NLS-1$
+ if (!newbieFile.createNewFile()) {
+ throw new IOException(newbieFile + " already exists.");
+ }
+ */
- } else {
- //File folder = new File(getTempFolder(), "build");
- //if (!folder.exists()) folder.mkdirs();
- buildFolder = createTempFolder("build");
- buildFolder.deleteOnExit();
+ // Create sketch properties file if it's not the default mode.
+ if (!nextMode.equals(getDefaultMode())) {
+ saveModeSettings(new File(newbieDir, "sketch.properties"), nextMode);
}
+
+ String path = newbieFile.getAbsolutePath();
+ /*Editor editor =*/ handleOpen(path, true);
+
+ } catch (IOException e) {
+ Messages.showWarning("That's new to me",
+ "A strange and unexplainable error occurred\n" +
+ "while trying to create a new sketch.", e);
}
- return buildFolder;
}
- */
/**
- * Create a temporary folder by using the createTempFile() mechanism,
- * deleting the file it creates, and making a folder using the location
- * that was provided.
- *
- * Unlike createTempFile(), there is no minimum size for prefix. If
- * prefix is less than 3 characters, the remaining characters will be
- * filled with underscores
+ * Prompt for a sketch to open, and open it in a new window.
*/
- static public File createTempFolder(String prefix, String suffix, File directory) throws IOException {
- int fillChars = 3 - prefix.length();
- for (int i = 0; i < fillChars; i++) {
- prefix += '_';
+ public void handleOpenPrompt() {
+ final StringList extensions = new StringList();
+ for (Mode mode : getModeList()) {
+ extensions.append(mode.getDefaultExtension());
}
- File folder = File.createTempFile(prefix, suffix, directory);
- // Now delete that file and create a folder in its place
- folder.delete();
- folder.mkdirs();
- // And send the folder back to your friends
- return folder;
- }
-
-
- static public File getToolsFolder() {
- return getContentFile("tools");
- }
-
- static public void locateSketchbookFolder() {
- // If a value is at least set, first check to see if the folder exists.
- // If it doesn't, warn the user that the sketchbook folder is being reset.
- String sketchbookPath = Preferences.getSketchbookPath();
- if (sketchbookPath != null) {
- sketchbookFolder = new File(sketchbookPath);
- if (!sketchbookFolder.exists()) {
- Base.showWarning("Sketchbook folder disappeared",
- "The sketchbook folder no longer exists.\n" +
- "Processing will switch to the default sketchbook\n" +
- "location, and create a new sketchbook folder if\n" +
- "necessary. Processing will then stop talking\n" +
- "about himself in the third person.", null);
- sketchbookFolder = null;
- }
- }
- // If no path is set, get the default sketchbook folder for this platform
- if (sketchbookFolder == null) {
- sketchbookFolder = getDefaultSketchbookFolder();
- Preferences.setSketchbookPath(sketchbookFolder.getAbsolutePath());
- if (!sketchbookFolder.exists()) {
- sketchbookFolder.mkdirs();
- }
- }
+ final String prompt = Language.text("open");
- getSketchbookLibrariesFolder().mkdir();
- getSketchbookToolsFolder().mkdir();
- getSketchbookModesFolder().mkdir();
- getSketchbookExamplesPackagesFolder().mkdir();
-// System.err.println("sketchbook: " + sketchbookFolder);
- }
+ // don't use native dialogs on Linux (or anyone else w/ override)
+ if (Preferences.getBoolean("chooser.files.native")) { //$NON-NLS-1$
+ // use the front-most window frame for placing file dialog
+ FileDialog openDialog =
+ new FileDialog(activeEditor, prompt, FileDialog.LOAD);
+ // Only show .pde files as eligible bachelors
+ openDialog.setFilenameFilter(new FilenameFilter() {
+ public boolean accept(File dir, String name) {
+ // confirmed to be working properly [fry 110128]
+ for (String ext : extensions) {
+ if (name.toLowerCase().endsWith("." + ext)) { //$NON-NLS-1$
+ return true;
+ }
+ }
+ return false;
+ }
+ });
- public void setSketchbookFolder(File folder) {
- sketchbookFolder = folder;
- Preferences.setSketchbookPath(folder.getAbsolutePath());
- rebuildSketchbookMenus();
- }
+ openDialog.setVisible(true);
+ String directory = openDialog.getDirectory();
+ String filename = openDialog.getFile();
+ if (filename != null) {
+ File inputFile = new File(directory, filename);
+ handleOpen(inputFile.getAbsolutePath());
+ }
- static public File getSketchbookFolder() {
- return sketchbookFolder;
- }
+ } else {
+ if (openChooser == null) {
+ openChooser = new JFileChooser();
+ }
+ openChooser.setDialogTitle(prompt);
+ openChooser.setFileFilter(new javax.swing.filechooser.FileFilter() {
+ public boolean accept(File file) {
+ // JFileChooser requires you to explicitly say yes to directories
+ // as well (unlike the AWT chooser). Useful, but... different.
+ // http://code.google.com/p/processing/issues/detail?id=1151
+ if (file.isDirectory()) {
+ return true;
+ }
+ for (String ext : extensions) {
+ if (file.getName().toLowerCase().endsWith("." + ext)) { //$NON-NLS-1$
+ return true;
+ }
+ }
+ return false;
+ }
- static public File getSketchbookLibrariesFolder() {
- return new File(sketchbookFolder, "libraries");
+ public String getDescription() {
+ return "Processing Sketch";
+ }
+ });
+ if (openChooser.showOpenDialog(activeEditor) == JFileChooser.APPROVE_OPTION) {
+ handleOpen(openChooser.getSelectedFile().getAbsolutePath());
+ }
+ }
}
- static public File getSketchbookToolsFolder() {
- return new File(sketchbookFolder, "tools");
+ /**
+ * Open a sketch from the path specified. Do not use for untitled sketches.
+ */
+ public Editor handleOpen(String path) {
+ return handleOpen(path, false);
}
- static public File getSketchbookModesFolder() {
- return new File(sketchbookFolder, "modes");
+ /**
+ * Open a sketch in a new window.
+ * @param path Path to the pde file for the sketch in question
+ * @return the Editor object, so that properties (like 'untitled')
+ * can be set by the caller
+ */
+ public Editor handleOpen(String path, boolean untitled) {
+ return handleOpen(path, untitled, new EditorState(editors));
}
- static public File getSketchbookExamplesPackagesFolder() {
- return new File(sketchbookFolder, "examples-packages");
- }
+ protected Editor handleOpen(String path, boolean untitled,
+ EditorState state) {
+ try {
+ // System.err.println("entering handleOpen " + path);
+ final File file = new File(path);
+ if (!file.exists()) {
+ return null;
+ }
- static protected File getDefaultSketchbookFolder() {
- File sketchbookFolder = null;
- try {
- sketchbookFolder = platform.getDefaultSketchbookFolder();
- } catch (Exception e) { }
+ // Cycle through open windows to make sure that it's not already open.
+ for (Editor editor : editors) {
+ // User may have double-clicked any PDE in the sketch folder,
+ // so we have to check each open tab (not just the main one).
+ // https://github.com/processing/processing/issues/2506
+ for (SketchCode tab : editor.getSketch().getCode()) {
+ if (tab.getFile().equals(file)) {
+ editor.toFront();
+ // move back to the top of the recent list
+ Recent.append(editor);
+ return editor;
+ }
+ }
+ }
- if (sketchbookFolder == null) {
- showError("No sketchbook",
- "Problem while trying to get the sketchbook", null);
- }
+ if (!Sketch.isSanitaryName(file.getName())) {
+ Messages.showWarning("You're tricky, but not tricky enough",
+ file.getName() + " is not a valid name for a sketch.\n" +
+ "Better to stick to ASCII, no spaces, and make sure\n" +
+ "it doesn't start with a number.", null);
+ return null;
+ }
- // create the folder if it doesn't exist already
- boolean result = true;
- if (!sketchbookFolder.exists()) {
- result = sketchbookFolder.mkdirs();
- }
+ if (!nextMode.canEdit(file)) {
+ final Mode mode = selectMode(file);
+ if (mode == null) {
+ return null;
+ }
+ nextMode = mode;
+ }
- if (!result) {
- showError("You forgot your sketchbook",
- "Processing cannot run because it could not\n" +
- "create a folder to store your sketchbook.", null);
- }
+ try {
+ Editor editor = nextMode.createEditor(this, path, state);
- return sketchbookFolder;
- }
+ editor.setUpdatesAvailable(updatesAvailable);
+ // opened successfully, let's go to work
+ editor.getSketch().setUntitled(untitled);
+ editors.add(editor);
+ Recent.append(editor);
-// /**
-// * Check for a new sketchbook location.
-// */
-// static protected File promptSketchbookLocation() {
-// // Most often this will happen on Linux, so default to their home dir.
-// File folder = new File(System.getProperty("user.home"), "sketchbook");
-// String prompt = "Select a folder to place sketches...";
-//
-//// FolderSelector fs = new FolderSelector(prompt, folder, new Frame());
-//// folder = fs.getFolder();
-// folder = Base.selectFolder(prompt, folder, new Frame());
-//
-//// folder = Base.selectFolder(prompt, folder, null);
-//// PApplet.selectFolder(prompt,
-//// "promptSketchbookCallback", dflt,
-//// Preferences.this, dialog);
-//
-// if (folder == null) {
-// System.exit(0);
-// }
-// // Create the folder if it doesn't exist already
-// if (!folder.exists()) {
-// folder.mkdirs();
-// return folder;
-// }
-// return folder;
-// }
+ // now that we're ready, show the window
+ // (don't do earlier, cuz we might move it based on a window being closed)
+ editor.setVisible(true);
+ return editor;
- // .................................................................
+ } catch (EditorException ee) {
+ if (ee.getMessage() != null) { // null if the user canceled
+ Messages.showWarning("Error opening sketch", ee.getMessage(), ee);
+ }
+ } catch (NoSuchMethodError nsme) {
+ Messages.showWarning("Mode out of date",
+ nextMode.getTitle() + " is not compatible with this version of Processing.\n" +
+ "Try updating the Mode or contact its author for a new version.", nsme);
+ } catch (Throwable t) {
+ if (nextMode.equals(getDefaultMode())) {
+ Messages.showTrace("Serious Problem",
+ "An unexpected, unknown, and unrecoverable error occurred\n" +
+ "while opening a new editor window. Please report this.", t, true);
+ } else {
+ Messages.showTrace("Mode Problems",
+ "A nasty error occurred while trying to use " + nextMode.getTitle() + ".\n" +
+ "It may not be compatible with this version of Processing.\n" +
+ "Try updating the Mode or contact its author for a new version.", t, false);
+ }
+ }
+ if (editors.isEmpty()) {
+ Mode defaultMode = getDefaultMode();
+ if (nextMode == defaultMode) {
+ // unreachable? hopefully?
+ Messages.showError("Editor Problems",
+ "An error occurred while trying to change modes.\n" +
+ "We'll have to quit for now because it's an\n" +
+ "unfortunate bit of indigestion with the default Mode.",
+ null);
+ } else {
+ // Don't leave the user hanging or the PDE locked up
+ // https://github.com/processing/processing/issues/4467
+ if (untitled) {
+ nextMode = defaultMode;
+ handleNew();
+ return null; // ignored by any caller
+ } else {
+ // This null response will be kicked back to changeMode(),
+ // signaling it to re-open the sketch in the default Mode.
+ return null;
+ }
+ }
+ }
- /**
- * Implements the cross-platform headache of opening URLs.
- *
- * For 2.0a8 and later, this requires the parameter to be an actual URL,
- * meaning that you can't send it a file:// path without a prefix. It also
- * just calls into Platform, which now uses java.awt.Desktop (where
- * possible, meaning not on Linux) now that we're requiring Java 6.
- * As it happens the URL must also be properly URL-encoded.
- */
- static public void openURL(String url) {
- try {
- platform.openURL(url);
+ /*
+ if (editors.isEmpty()) {
+ // if the bad mode is the default mode, don't go into an infinite loop
+ // trying to recreate a window with the default mode.
+ Mode defaultMode = getDefaultMode();
+ if (nextMode == defaultMode) {
+ Base.showError("Editor Problems",
+ "An error occurred while trying to change modes.\n" +
+ "We'll have to quit for now because it's an\n" +
+ "unfortunate bit of indigestion with the default Mode.",
+ null);
+ } else {
+ editor = defaultMode.createEditor(this, path, state);
+ }
+ }
+ */
- } catch (Exception e) {
- showWarning("Problem Opening URL",
- "Could not open the URL\n" + url, e);
+ } catch (Throwable t) {
+ Messages.showTrace("Terrible News",
+ "A serious error occurred while " +
+ "trying to create a new editor window.", t,
+ nextMode == getDefaultMode()); // quit if default
+ nextMode = getDefaultMode();
}
+ return null;
}
- /**
- * Used to determine whether to disable the "Show Sketch Folder" option.
- * @return true If a means of opening a folder is known to be available.
- */
- static protected boolean openFolderAvailable() {
- return platform.openFolderAvailable();
- }
+ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
/**
- * Implements the other cross-platform headache of opening
- * a folder in the machine's native file browser.
+ * Close a sketch as specified by its editor window.
+ * @param editor Editor object of the sketch to be closed.
+ * @param modeSwitch Whether this close is being done in the context of a
+ * mode switch.
+ * @return true if succeeded in closing, false if canceled.
*/
- static public void openFolder(File file) {
- try {
- platform.openFolder(file);
-
- } catch (Exception e) {
- showWarning("Problem Opening Folder",
- "Could not open the folder\n" + file.getAbsolutePath(), e);
+ public boolean handleClose(Editor editor, boolean modeSwitch) {
+ // Check if modified
+// boolean immediate = editors.size() == 1;
+ if (!editor.checkModified()) {
+ return false;
}
- }
-
-
- // .................................................................
-
-
-// /**
-// * Prompt for a folder and return it as a File object (or null).
-// * Implementation for choosing directories that handles both the
-// * Mac OS X hack to allow the native AWT file dialog, or uses
-// * the JFileChooser on other platforms. Mac AWT trick obtained from
-// * this post
-// * on the OS X Java dev archive which explains the cryptic note in
-// * Apple's Java 1.4 release docs about the special System property.
-// */
-// static public File selectFolder(String prompt, File folder, Frame frame) {
-// if (Base.isMacOS()) {
-// if (frame == null) frame = new Frame(); //.pack();
-// FileDialog fd = new FileDialog(frame, prompt, FileDialog.LOAD);
-// if (folder != null) {
-// fd.setDirectory(folder.getParent());
-// //fd.setFile(folder.getName());
-// }
-// System.setProperty("apple.awt.fileDialogForDirectories", "true");
-// fd.setVisible(true);
-// System.setProperty("apple.awt.fileDialogForDirectories", "false");
-// if (fd.getFile() == null) {
-// return null;
-// }
-// return new File(fd.getDirectory(), fd.getFile());
-//
-// } else {
-// JFileChooser fc = new JFileChooser();
-// fc.setDialogTitle(prompt);
-// if (folder != null) {
-// fc.setSelectedFile(folder);
-// }
-// fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
-//
-// int returned = fc.showOpenDialog(new JDialog());
-// if (returned == JFileChooser.APPROVE_OPTION) {
-// return fc.getSelectedFile();
-// }
-// }
-// return null;
-// }
-
-
-// static class FolderSelector {
-// File folder;
-// boolean ready;
-//
-// FolderSelector(String prompt, File defaultFile, Frame parentFrame) {
-// PApplet.selectFolder(prompt, "callback", defaultFile, this, parentFrame);
-// }
-//
-// public void callback(File folder) {
-// this.folder = folder;
-// ready = true;
-// }
-//
-// boolean isReady() {
-// return ready;
-// }
-//
-// /** block until the folder is available */
-// File getFolder() {
-// while (!ready) {
-// try {
-// Thread.sleep(100);
-// } catch (InterruptedException e) { }
-// }
-// return folder;
-// }
-// }
-//
-//
-// /**
-// * Blocking version of folder selection. Runs and sleeps until an answer
-// * comes back. Avoid using: try to make things work with the async
-// * selectFolder inside PApplet instead.
-// */
-// static public File selectFolder(String prompt, File folder, Frame frame) {
-// return new FolderSelector(prompt, folder, frame).getFolder();
-// }
+ // Close the running window, avoid window boogers with multiple sketches
+ editor.internalCloseRunner();
+
+// System.out.println("editors size is " + editors.size());
+ if (editors.size() == 1) {
+ // For 0158, when closing the last window /and/ it was already an
+ // untitled sketch, just give up and let the user quit.
+// if (Preferences.getBoolean("sketchbook.closing_last_window_quits") ||
+// (editor.untitled && !editor.getSketch().isModified())) {
+ if (Platform.isMacOS()) {
+ // If the central menubar isn't supported on this OS X JVM,
+ // we have to do the old behavior. Yuck!
+ if (defaultFileMenu == null) {
+ Object[] options = { Language.text("prompt.ok"), Language.text("prompt.cancel") };
+ String prompt =
+ " " +
+ " " +
+ "Are you sure you want to Quit?" +
+ "
Closing the last open sketch will quit Processing.";
+
+ int result = JOptionPane.showOptionDialog(editor,
+ prompt,
+ "Quit",
+ JOptionPane.YES_NO_OPTION,
+ JOptionPane.QUESTION_MESSAGE,
+ null,
+ options,
+ options[0]);
+ if (result == JOptionPane.NO_OPTION ||
+ result == JOptionPane.CLOSED_OPTION) {
+ return false;
+ }
+ }
+ }
- // .................................................................
+ Preferences.unset("server.port"); //$NON-NLS-1$
+ Preferences.unset("server.key"); //$NON-NLS-1$
+// // This will store the sketch count as zero
+// editors.remove(editor);
+// System.out.println("editors size now " + editors.size());
+// storeSketches();
- /**
- * "No cookie for you" type messages. Nothing fatal or all that
- * much of a bummer, but something to notify the user about.
- */
- static public void showMessage(String title, String message) {
- if (title == null) title = "Message";
+ // Save out the current prefs state
+ Preferences.save();
- if (commandLine) {
- System.out.println(title + ": " + message);
+ if (defaultFileMenu == null) {
+ if (modeSwitch) {
+ // need to close this editor, ever so temporarily
+ editor.setVisible(false);
+ editor.dispose();
+ activeEditor = null;
+ editors.remove(editor);
+ } else {
+ // Since this wasn't an actual Quit event, call System.exit()
+ System.exit(0);
+ }
+ } else { // on OS X, update the default file menu
+ editor.setVisible(false);
+ editor.dispose();
+ defaultFileMenu.insert(Recent.getMenu(), 2);
+ activeEditor = null;
+ editors.remove(editor);
+ }
} else {
- JOptionPane.showMessageDialog(new Frame(), message, title,
- JOptionPane.INFORMATION_MESSAGE);
+ // More than one editor window open,
+ // proceed with closing the current window.
+ editor.setVisible(false);
+ editor.dispose();
+ editors.remove(editor);
}
+ return true;
}
/**
- * Non-fatal error message.
+ * Handler for File → Quit.
+ * @return false if canceled, true otherwise.
*/
- static public void showWarning(String title, String message) {
- showWarning(title, message, null);
- }
+ public boolean handleQuit() {
+ // If quit is canceled, this will be replaced anyway
+ // by a later handleQuit() that is not canceled.
+// storeSketches();
- /**
- * Non-fatal error message with optional stack trace side dish.
- */
- static public void showWarning(String title, String message, Throwable e) {
- if (title == null) title = "Warning";
+ if (handleQuitEach()) {
+ // make sure running sketches close before quitting
+ for (Editor editor : editors) {
+ editor.internalCloseRunner();
+ }
+ // Save out the current prefs state
+ Preferences.save();
- if (commandLine) {
- System.out.println(title + ": " + message);
+ // Finished with this guy
+ Console.shutdown();
- } else {
- JOptionPane.showMessageDialog(new Frame(), message, title,
- JOptionPane.WARNING_MESSAGE);
+ if (!Platform.isMacOS()) {
+ // If this was fired from the menu or an AppleEvent (the Finder),
+ // then Mac OS X will send the terminate signal itself.
+ System.exit(0);
+ }
+ return true;
}
- if (e != null) e.printStackTrace();
+ return false;
}
/**
- * Non-fatal error message with optional stack trace side dish.
+ * Attempt to close each open sketch in preparation for quitting.
+ * @return false if canceled along the way
*/
- static public void showWarningTiered(String title,
- String primary, String secondary,
- Throwable e) {
- if (title == null) title = "Warning";
-
- final String message = primary + "\n" + secondary;
- if (commandLine) {
- System.out.println(title + ": " + message);
-
- } else {
-// JOptionPane.showMessageDialog(new Frame(), message,
-// title, JOptionPane.WARNING_MESSAGE);
- if (!Base.isMacOS()) {
- JOptionPane.showMessageDialog(new JFrame(),
- "
",
- JOptionPane.QUESTION_MESSAGE);
-
- String[] options = new String[] {
- Language.text("save.btn.save"), Language.text("prompt.cancel"), Language.text("save.btn.dont_save")
- };
- pane.setOptions(options);
-
- // highlight the safest option ala apple hig
- pane.setInitialValue(options[0]);
-
- // on macosx, setting the destructive property places this option
- // away from the others at the lefthand side
- pane.putClientProperty("Quaqua.OptionPane.destructiveOption",
- Integer.valueOf(2));
-
- JDialog dialog = pane.createDialog(editor, null);
- dialog.setVisible(true);
-
- Object result = pane.getValue();
- if (result == options[0]) {
- return JOptionPane.YES_OPTION;
- } else if (result == options[1]) {
- return JOptionPane.CANCEL_OPTION;
- } else if (result == options[2]) {
- return JOptionPane.NO_OPTION;
- } else {
- return JOptionPane.CLOSED_OPTION;
- }
+ public void populateSketchbookMenu(JMenu menu) {
+ boolean found = false;
+ try {
+ found = addSketches(menu, sketchbookFolder, false);
+ } catch (IOException e) {
+ Messages.showWarning("Sketchbook Menu Error",
+ "An error occurred while trying to list the sketchbook.", e);
+ }
+ if (!found) {
+ JMenuItem empty = new JMenuItem(Language.text("menu.file.sketchbook.empty"));
+ empty.setEnabled(false);
+ menu.add(empty);
}
}
-//if (result == JOptionPane.YES_OPTION) {
- //
-// } else if (result == JOptionPane.NO_OPTION) {
-// return true; // ok to continue
- //
-// } else if (result == JOptionPane.CANCEL_OPTION) {
-// return false;
- //
-// } else {
-// throw new IllegalStateException();
-// }
+ /*
+ public JMenu getRecentMenu() {
+ return recent.getMenu();
+ }
- static public int showYesNoQuestion(Frame editor, String title,
- String primary, String secondary) {
- if (!Base.isMacOS()) {
- return JOptionPane.showConfirmDialog(editor,
- "" +
- "" + primary + "" +
- " " + secondary, title,
- JOptionPane.YES_NO_OPTION,
- JOptionPane.QUESTION_MESSAGE);
- } else {
- // Pane formatting adapted from the Quaqua guide
- // http://www.randelshofer.ch/quaqua/guide/joptionpane.html
- JOptionPane pane =
- new JOptionPane(" " +
- " " +
- "" + primary + "" +
- "
" + secondary + "
",
- JOptionPane.QUESTION_MESSAGE);
-
- String[] options = new String[] {
- "Yes", "No"
- };
- pane.setOptions(options);
- // highlight the safest option ala apple hig
- pane.setInitialValue(options[0]);
+ public JMenu getToolbarRecentMenu() {
+ return recent.getToolbarMenu();
+ }
- JDialog dialog = pane.createDialog(editor, null);
- dialog.setVisible(true);
- Object result = pane.getValue();
- if (result == options[0]) {
- return JOptionPane.YES_OPTION;
- } else if (result == options[1]) {
- return JOptionPane.NO_OPTION;
- } else {
- return JOptionPane.CLOSED_OPTION;
- }
- }
+ public void handleRecent(Editor editor) {
+ recent.handle(editor);
}
- /**
- * Retrieve a path to something in the Processing folder. Eventually this
- * may refer to the Contents subfolder of Processing.app, if we bundle things
- * up as a single .app file with no additional folders.
- */
-// static public String getContentsPath(String filename) {
-// String basePath = System.getProperty("user.dir");
-// /*
-// // do this later, when moving to .app package
-// if (PApplet.platform == PConstants.MACOSX) {
-// basePath = System.getProperty("processing.contents");
-// }
-// */
-// return basePath + File.separator + filename;
-// }
+ public void handleRecentRename(Editor editor, String oldPath) {
+ recent.handleRename(editor, oldPath);
+ }
- /**
- * Get a path for something in the Processing lib folder.
- */
- /*
- static public String getLibContentsPath(String filename) {
- String libPath = getContentsPath("lib/" + filename);
- File libDir = new File(libPath);
- if (libDir.exists()) {
- return libPath;
- }
-// was looking into making this run from Eclipse, but still too much mess
-// libPath = getContents("build/shared/lib/" + what);
-// libDir = new File(libPath);
-// if (libDir.exists()) {
-// return libPath;
-// }
- return null;
+ // Called before a sketch is renamed so that its old name is
+ // no longer in the menu.
+ public void removeRecent(Editor editor) {
+ recent.remove(editor);
}
*/
+
/**
- * Adjacent the executable on Windows and Linux,
- * or inside Contents/Resources/Java on Mac OS X.
+ * Scan a folder recursively, and add any sketches found to the menu
+ * specified. Set the openReplaces parameter to true when opening the sketch
+ * should replace the sketch in the current window, or false when the
+ * sketch should open in a new window.
*/
- static protected File processingRoot;
-
- static public File getContentFile(String name) {
- if (processingRoot == null) {
- // Get the path to the .jar file that contains Base.class
- String path = Base.class.getProtectionDomain().getCodeSource().getLocation().getPath();
- // Path may have URL encoding, so remove it
- String decodedPath = PApplet.urlDecode(path);
-
- if (decodedPath.contains("/app/bin")) {
- if (Base.isMacOS()) {
- processingRoot =
- new File(path, "../../build/macosx/work/Processing.app/Contents/Java");
- } else if (Base.isWindows()) {
- processingRoot = new File(path, "../../build/windows/work");
- } else if (Base.isLinux()) {
- processingRoot = new File(path, "../../build/linux/work");
- }
- } else {
- // The .jar file will be in the lib folder
- File jarFolder = new File(decodedPath).getParentFile();
- if (jarFolder.getName().equals("lib")) {
- // The main Processing installation directory.
- // This works for Windows, Linux, and Apple's Java 6 on OS X.
- processingRoot = jarFolder.getParentFile();
- } else if (Base.isMacOS()) {
- // This works for Java 7 on OS X. The 'lib' folder is not part of the
- // classpath on OS X, and adding it creates more problems than it's
- // worth.
- processingRoot = jarFolder;
+ protected boolean addSketches(JMenu menu, File folder,
+ final boolean replaceExisting) throws IOException {
+ // skip .DS_Store files, etc (this shouldn't actually be necessary)
+ if (!folder.isDirectory()) {
+ return false;
+ }
- }
- if (processingRoot == null || !processingRoot.exists()) {
- // Try working directory instead (user.dir, different from user.home)
- System.err.println("Could not find lib folder via " +
- jarFolder.getAbsolutePath() +
- ", switching to user.dir");
- processingRoot = new File(System.getProperty("user.dir"));
- }
- }
+ if (folder.getName().equals("libraries")) {
+ return false; // let's not go there
}
-/*
- String path = System.getProperty("user.dir");
-
- // Get a path to somewhere inside the .app folder
- if (Base.isMacOS()) {
-// javaroot
-// $JAVAROOT
- String javaroot = System.getProperty("javaroot");
- if (javaroot != null) {
- path = javaroot;
+
+ if (folder.getName().equals("sdk")) {
+ // This could be Android's SDK folder. Let's double check:
+ File suspectSDKPath = new File(folder.getParent(), folder.getName());
+ File expectedSDKPath = new File(sketchbookFolder, "android" + File.separator + "sdk");
+ if (expectedSDKPath.getAbsolutePath().equals(suspectSDKPath.getAbsolutePath())) {
+ return false; // Most likely the SDK folder, skip it
}
}
- File working = new File(path);
- */
- return new File(processingRoot, name);
- }
+ String[] list = folder.list();
+ // If a bad folder or unreadable or whatever, this will come back null
+ if (list == null) {
+ return false;
+ }
+
+ // Alphabetize the list, since it's not always alpha order
+ Arrays.sort(list, String.CASE_INSENSITIVE_ORDER);
+
+ ActionListener listener = new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ String path = e.getActionCommand();
+ if (new File(path).exists()) {
+ boolean replace = replaceExisting;
+ if ((e.getModifiers() & ActionEvent.SHIFT_MASK) != 0) {
+ replace = !replace;
+ }
+// if (replace) {
+// handleOpenReplace(path);
+// } else {
+ handleOpen(path);
+// }
+ } else {
+ Messages.showWarning("Sketch Disappeared",
+ "The selected sketch no longer exists.\n" +
+ "You may need to restart Processing to update\n" +
+ "the sketchbook menu.", null);
+ }
+ }
+ };
+ // offers no speed improvement
+ //menu.addActionListener(listener);
+
+ boolean found = false;
+
+// for (int i = 0; i < list.length; i++) {
+// if ((list[i].charAt(0) == '.') ||
+// list[i].equals("CVS")) continue;
+ for (String name : list) {
+ if (name.charAt(0) == '.') {
+ continue;
+ }
+
+ File subfolder = new File(folder, name);
+ if (subfolder.isDirectory()) {
+ File entry = checkSketchFolder(subfolder, name);
+ if (entry != null) {
+
+ JMenuItem item = new JMenuItem(name);
+ item.addActionListener(listener);
+ item.setActionCommand(entry.getAbsolutePath());
+ menu.add(item);
+ found = true;
- static public File getJavaHome() {
- if (isMacOS()) {
- //return "Contents/PlugIns/jdk1.7.0_40.jdk/Contents/Home/jre/bin/java";
- File[] plugins = getContentFile("../PlugIns").listFiles(new FilenameFilter() {
- public boolean accept(File dir, String name) {
- return dir.isDirectory() &&
- name.endsWith(".jdk") && !name.startsWith(".");
+ } else {
+ // not a sketch folder, but maybe a subfolder containing sketches
+ JMenu submenu = new JMenu(name);
+ // needs to be separate var otherwise would set ifound to false
+ boolean anything = addSketches(submenu, subfolder, replaceExisting);
+ if (anything && !name.equals("old")) { //Don't add old contributions
+ menu.add(submenu);
+ found = true;
+ }
}
- });
- return new File(plugins[0], "Contents/Home/jre");
+ }
}
- // On all other platforms, it's the 'java' folder adjacent to Processing
- return getContentFile("java");
+ return found;
}
- /** Get the path to the embedded Java executable. */
- static public String getJavaPath() {
- String javaPath = "bin/java" + (isWindows() ? ".exe" : "");
- File javaFile = new File(getJavaHome(), javaPath);
- try {
- return javaFile.getCanonicalPath();
- } catch (IOException e) {
- return javaFile.getAbsolutePath();
+ public boolean addSketches(DefaultMutableTreeNode node, File folder,
+ boolean examples) throws IOException {
+ // skip .DS_Store files, etc (this shouldn't actually be necessary)
+ if (!folder.isDirectory()) {
+ return false;
}
- /*
- if (isMacOS()) {
- //return "Contents/PlugIns/jdk1.7.0_40.jdk/Contents/Home/jre/bin/java";
- File[] plugins = getContentFile("../PlugIns").listFiles(new FilenameFilter() {
- public boolean accept(File dir, String name) {
- return name.endsWith(".jdk") && dir.isDirectory();
- }
- });
- //PApplet.printArray(plugins);
- File javaBinary = new File(plugins[0], "Contents/Home/jre/bin/java");
- //return getContentFile(plugins[0].getAbsolutePath() + "/Contents/Home/jre/bin/java").getAbsolutePath();
- //return getContentFile("../PlugIns/jdk1.7.0_40.jdk/Contents/Home/jre/bin/java").getAbsolutePath();
- return javaBinary.getAbsolutePath();
- } else if (isLinux()) {
- return getContentFile("java/bin/java").getAbsolutePath();
+ final String folderName = folder.getName();
- } else if (isWindows()) {
- return getContentFile("java/bin/java.exe").getAbsolutePath();
+ // Don't look inside the 'libraries' folders in the sketchbook
+ if (folderName.equals("libraries")) {
+ return false;
}
- System.err.println("No appropriate platform found. " +
- "Hoping that Java is in the path.");
- return Base.isWindows() ? "java.exe" : "java";
- */
- }
-
-
-// /**
-// * Get an image associated with the current color theme.
-// * @deprecated
-// */
-// static public Image getThemeImage(String name, Component who) {
-// return getLibImage("theme/" + name, who);
-// }
-//
-//
-// /**
-// * Return an Image object from inside the Processing lib folder.
-// * @deprecated
-// */
-// static public Image getLibImage(String name, Component who) {
-// Image image = null;
-//// Toolkit tk = Toolkit.getDefaultToolkit();
-//
-// File imageLocation = new File(getContentFile("lib"), name);
-// image = java.awt.Toolkit.getDefaultToolkit().getImage(imageLocation.getAbsolutePath());
-// MediaTracker tracker = new MediaTracker(who);
-// tracker.addImage(image, 0);
-// try {
-// tracker.waitForAll();
-// } catch (InterruptedException e) { }
-// return image;
-// }
-
-
- /**
- * Return an InputStream for a file inside the Processing lib folder.
- */
- static public InputStream getLibStream(String filename) throws IOException {
- return new FileInputStream(new File(getContentFile("lib"), filename));
- }
-
- // ...................................................................
-
-
- /**
- * Get the number of lines in a file by counting the number of newline
- * characters inside a String (and adding 1).
- */
- static public int countLines(String what) {
- int count = 1;
- for (char c : what.toCharArray()) {
- if (c == '\n') count++;
+ // When building the sketchbook, don't show the contributed 'examples'
+ // like it's a subfolder. But when loading examples, allow the folder
+ // to be named 'examples'.
+ if (!examples && folderName.equals("examples")) {
+ return false;
}
- return count;
- }
+// // Conversely, when looking for examples, ignore the other folders
+// // (to avoid going through hoops with the tree node setup).
+// if (examples && !folderName.equals("examples")) {
+// return false;
+// }
+// // Doesn't quite work because the parent will be 'examples', and we want
+// // to walk inside that, but the folder itself will have a different name
- /**
- * Same as PApplet.loadBytes(), however never does gzip decoding.
- */
- static public byte[] loadBytesRaw(File file) throws IOException {
- int size = (int) file.length();
- FileInputStream input = new FileInputStream(file);
- byte buffer[] = new byte[size];
- int offset = 0;
- int bytesRead;
- while ((bytesRead = input.read(buffer, offset, size-offset)) != -1) {
- offset += bytesRead;
- if (bytesRead == 0) break;
+ String[] fileList = folder.list();
+ // If a bad folder or unreadable or whatever, this will come back null
+ if (fileList == null) {
+ return false;
}
- input.close(); // weren't properly being closed
- input = null;
- return buffer;
- }
+ // Alphabetize the list, since it's not always alpha order
+ Arrays.sort(fileList, String.CASE_INSENSITIVE_ORDER);
- /**
- * Read from a file with a bunch of attribute/value pairs
- * that are separated by = and ignore comments with #.
- */
- static public HashMap readSettings(File inputFile) {
- HashMap outgoing = new HashMap();
- if (inputFile.exists()) {
- String lines[] = PApplet.loadStrings(inputFile);
- readSettings(inputFile.toString(), lines, outgoing);
- }
- return outgoing;
- }
+ boolean found = false;
+ for (String name : fileList) {
+ if (name.charAt(0) == '.') { // Skip hidden files
+ continue;
+ }
+ File subfolder = new File(folder, name);
+ if (subfolder.isDirectory()) {
+ File entry = checkSketchFolder(subfolder, name);
+ if (entry != null) {
+ DefaultMutableTreeNode item =
+ new DefaultMutableTreeNode(new SketchReference(name, entry));
+
+ node.add(item);
+ found = true;
- /**
- * Parse a String array that contains attribute/value pairs separated
- * by = (the equals sign). The # (hash) symbol is used to denote comments.
- * Comments can be anywhere on a line. Blank lines are ignored.
- */
- static public void readSettings(String filename, String[] lines,
- HashMap settings) {
- for (String line : lines) {
- // Remove comments
- int commentMarker = line.indexOf('#');
- if (commentMarker != -1) {
- line = line.substring(0, commentMarker);
- }
- // Remove extra whitespace
- line = line.trim();
-
- if (line.length() != 0) {
- int equals = line.indexOf('=');
- if (equals == -1) {
- if (filename != null) {
- System.err.println("Ignoring illegal line in " + filename);
- System.err.println(" " + line);
- }
} else {
- String attr = line.substring(0, equals).trim();
- String valu = line.substring(equals + 1).trim();
- settings.put(attr, valu);
+ // not a sketch folder, but maybe a subfolder containing sketches
+ DefaultMutableTreeNode subnode = new DefaultMutableTreeNode(name);
+ // needs to be separate var otherwise would set ifound to false
+ boolean anything = addSketches(subnode, subfolder, examples);
+ if (anything) {
+ node.add(subnode);
+ found = true;
+ }
}
}
}
- }
-
-
- static public void copyFile(File sourceFile,
- File targetFile) throws IOException {
- BufferedInputStream from =
- new BufferedInputStream(new FileInputStream(sourceFile));
- BufferedOutputStream to =
- new BufferedOutputStream(new FileOutputStream(targetFile));
- byte[] buffer = new byte[16 * 1024];
- int bytesRead;
- while ((bytesRead = from.read(buffer)) != -1) {
- to.write(buffer, 0, bytesRead);
- }
- from.close();
- from = null;
-
- to.flush();
- to.close();
- to = null;
-
- targetFile.setLastModified(sourceFile.lastModified());
- targetFile.setExecutable(sourceFile.canExecute());
- }
-
-
- /**
- * Grab the contents of a file as a string.
- */
- static public String loadFile(File file) throws IOException {
- String[] contents = PApplet.loadStrings(file);
- if (contents == null) return null;
- return PApplet.join(contents, "\n");
+ return found;
}
/**
- * Spew the contents of a String object out to a file.
+ * Check through the various modes and see if this is a legit sketch.
+ * Because the default mode will be the first in the list, this will always
+ * prefer that one over the others.
*/
- static public void saveFile(String str, File file) throws IOException {
- File temp = File.createTempFile(file.getName(), null, file.getParentFile());
- try{
- // fix from cjwant to prevent symlinks from being destroyed.
- File canon = file.getCanonicalFile();
- file = canon;
- } catch (IOException e) {
- throw new IOException("Could not resolve canonical representation of " +
- file.getAbsolutePath());
- }
- PApplet.saveStrings(temp, new String[] { str });
- if (file.exists()) {
- boolean result = file.delete();
- if (!result) {
- throw new IOException("Could not remove old version of " +
- file.getAbsolutePath());
+ File checkSketchFolder(File subfolder, String item) {
+ for (Mode mode : getModeList()) {
+ File entry = new File(subfolder, item + "." + mode.getDefaultExtension()); //$NON-NLS-1$
+ // if a .pde file of the same prefix as the folder exists..
+ if (entry.exists()) {
+ return entry;
}
}
- boolean result = temp.renameTo(file);
- if (!result) {
- throw new IOException("Could not replace " +
- file.getAbsolutePath());
- }
+ return null;
}
+ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+
+
/**
- * Copy a folder from one place to another. This ignores all dot files and
- * folders found in the source directory, to avoid copying silly .DS_Store
- * files and potentially troublesome .svn folders.
+ * Show the Preferences window.
*/
- static public void copyDir(File sourceDir,
- File targetDir) throws IOException {
- if (sourceDir.equals(targetDir)) {
- final String urDum = "source and target directories are identical";
- throw new IllegalArgumentException(urDum);
- }
- targetDir.mkdirs();
- String files[] = sourceDir.list();
- for (int i = 0; i < files.length; i++) {
- // Ignore dot files (.DS_Store), dot folders (.svn) while copying
- if (files[i].charAt(0) == '.') continue;
- //if (files[i].equals(".") || files[i].equals("..")) continue;
- File source = new File(sourceDir, files[i]);
- File target = new File(targetDir, files[i]);
- if (source.isDirectory()) {
- //target.mkdirs();
- copyDir(source, target);
- target.setLastModified(source.lastModified());
- } else {
- copyFile(source, target);
- }
+ public void handlePrefs() {
+ if (preferencesFrame == null) {
+ preferencesFrame = new PreferencesFrame(this);
}
+ preferencesFrame.showFrame();
}
- static public void copyDirNative(File sourceDir,
- File targetDir) throws IOException {
- Process process = null;
- if (Base.isMacOS() || Base.isLinux()) {
- process = Runtime.getRuntime().exec(new String[] {
- "cp", "-a", sourceDir.getAbsolutePath(), targetDir.getAbsolutePath()
- });
- } else {
- // TODO implement version that uses XCOPY here on Windows
- throw new RuntimeException("Not yet implemented on Windows");
- }
- try {
- int result = process.waitFor();
- if (result != 0) {
- throw new IOException("Error while copying (result " + result + ")");
- }
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
+ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
/**
- * Delete a file or directory in a platform-specific manner. Removes a File
- * object (a file or directory) from the system by placing it in the Trash
- * or Recycle Bin (if available) or simply deleting it (if not).
- *
- * When the file/folder is on another file system, it may simply be removed
- * immediately, without additional warning. So only use this if you want to,
- * you know, "delete" the subject in question.
- *
- * NOTE: Not yet tested nor ready for prime-time.
- *
- * @param file the victim (a directory or individual file)
- * @return true if all ends well
- * @throws IOException what went wrong
+ * Return a File from inside the Processing 'lib' folder.
*/
- static public boolean platformDelete(File file) throws IOException {
- return platform.deleteFile(file);
+ static public File getLibFile(String filename) throws IOException {
+ return new File(Platform.getContentFile("lib"), filename);
}
/**
- * Remove all files in a directory and the directory itself.
+ * Return an InputStream for a file inside the Processing lib folder.
*/
- static public void removeDir(File dir) {
- if (dir.exists()) {
- removeDescendants(dir);
- if (!dir.delete()) {
- System.err.println("Could not delete " + dir);
- }
- }
+ static public InputStream getLibStream(String filename) throws IOException {
+ return new FileInputStream(getLibFile(filename));
}
/**
- * Recursively remove all files within a directory,
- * used with removeDir(), or when the contents of a dir
- * should be removed, but not the directory itself.
- * (i.e. when cleaning temp files from lib/build)
+ * Get the directory that can store settings. (Library on OS X, App Data or
+ * something similar on Windows, a dot folder on Linux.) Removed this as a
+ * preference for 3.0a3 because we need this to be stable.
*/
- static public void removeDescendants(File dir) {
- if (!dir.exists()) return;
-
- String files[] = dir.list();
- for (int i = 0; i < files.length; i++) {
- if (files[i].equals(".") || files[i].equals("..")) continue;
- File dead = new File(dir, files[i]);
- if (!dead.isDirectory()) {
- if (!Preferences.getBoolean("compiler.save_build_files")) {
- if (!dead.delete()) {
- // temporarily disabled
- System.err.println("Could not delete " + dead);
- }
+ static public File getSettingsFolder() {
+ File settingsFolder = null;
+
+ try {
+ settingsFolder = Platform.getSettingsFolder();
+
+ // create the folder if it doesn't exist already
+ if (!settingsFolder.exists()) {
+ if (!settingsFolder.mkdirs()) {
+ Messages.showError("Settings issues",
+ "Processing cannot run because it could not\n" +
+ "create a folder to store your settings.\n" +
+ settingsFolder.getAbsolutePath(), null);
}
- } else {
- removeDir(dead);
- //dead.delete();
}
+ } catch (Exception e) {
+ Messages.showTrace("An rare and unknowable thing happened",
+ "Could not get the settings folder. Please report:\n" +
+ "http://github.com/processing/processing/issues/new",
+ e, true);
}
+ return settingsFolder;
}
/**
- * Calculate the size of the contents of a folder.
- * Used to determine whether sketches are empty or not.
- * Note that the function calls itself recursively.
+ * Convenience method to get a File object for the specified filename inside
+ * the settings folder. Used to get preferences and recent sketch files.
+ * @param filename A file inside the settings folder.
+ * @return filename wrapped as a File object inside the settings folder
*/
- static public int calcFolderSize(File folder) {
- int size = 0;
-
- String files[] = folder.list();
- // null if folder doesn't exist, happens when deleting sketch
- if (files == null) return -1;
-
- for (int i = 0; i < files.length; i++) {
- if (files[i].equals(".") ||
- files[i].equals("..") ||
- files[i].equals(".DS_Store")) continue;
- File fella = new File(folder, files[i]);
- if (fella.isDirectory()) {
- size += calcFolderSize(fella);
- } else {
- size += (int) fella.length();
- }
- }
- return size;
+ static public File getSettingsFile(String filename) {
+ return new File(getSettingsFolder(), filename);
}
- /**
- * Recursively creates a list of all files within the specified folder,
- * and returns a list of their relative paths.
- * Ignores any files/folders prefixed with a dot.
- */
-// static public String[] listFiles(String path, boolean relative) {
-// return listFiles(new File(path), relative);
-// }
-
-
- static public String[] listFiles(File folder, boolean relative) {
- String path = folder.getAbsolutePath();
- Vector vector = new Vector();
- listFiles(relative ? (path + File.separator) : "", path, null, vector);
- String outgoing[] = new String[vector.size()];
- vector.copyInto(outgoing);
- return outgoing;
+ static public File getToolsFolder() {
+ return Platform.getContentFile("tools");
}
- static public String[] listFiles(File folder, boolean relative, String extension) {
- String path = folder.getAbsolutePath();
- Vector vector = new Vector();
- if (extension != null) {
- if (!extension.startsWith(".")) {
- extension = "." + extension;
+ static public void locateSketchbookFolder() {
+ // If a value is at least set, first check to see if the folder exists.
+ // If it doesn't, warn the user that the sketchbook folder is being reset.
+ String sketchbookPath = Preferences.getSketchbookPath();
+ if (sketchbookPath != null) {
+ sketchbookFolder = new File(sketchbookPath);
+ if (!sketchbookFolder.exists()) {
+ Messages.showWarning("Sketchbook folder disappeared",
+ "The sketchbook folder no longer exists.\n" +
+ "Processing will switch to the default sketchbook\n" +
+ "location, and create a new sketchbook folder if\n" +
+ "necessary. Processing will then stop talking\n" +
+ "about itself in the third person.", null);
+ sketchbookFolder = null;
}
}
- listFiles(relative ? (path + File.separator) : "", path, extension, vector);
- String outgoing[] = new String[vector.size()];
- vector.copyInto(outgoing);
- return outgoing;
- }
-
- static protected void listFiles(String basePath,
- String path, String extension,
- Vector vector) {
- File folder = new File(path);
- String[] list = folder.list();
- if (list != null) {
- for (String item : list) {
- if (item.charAt(0) == '.') continue;
- if (extension == null || item.toLowerCase().endsWith(extension)) {
- File file = new File(path, item);
- String newPath = file.getAbsolutePath();
- if (newPath.startsWith(basePath)) {
- newPath = newPath.substring(basePath.length());
- }
- // only add if no ext or match
- if (extension == null || item.toLowerCase().endsWith(extension)) {
- vector.add(newPath);
- }
- if (file.isDirectory()) { // use absolute path
- listFiles(basePath, file.getAbsolutePath(), extension, vector);
- }
- }
+ // If no path is set, get the default sketchbook folder for this platform
+ if (sketchbookFolder == null) {
+ sketchbookFolder = getDefaultSketchbookFolder();
+ Preferences.setSketchbookPath(sketchbookFolder.getAbsolutePath());
+ if (!sketchbookFolder.exists()) {
+ sketchbookFolder.mkdirs();
}
}
+ makeSketchbookSubfolders();
}
- /**
- * @param folder source folder to search
- * @return a list of .jar and .zip files in that folder
- */
- static public File[] listJarFiles(File folder) {
- return folder.listFiles(new FilenameFilter() {
- public boolean accept(File dir, String name) {
- return (!name.startsWith(".") &&
- (name.toLowerCase().endsWith(".jar") ||
- name.toLowerCase().endsWith(".zip")));
- }
- });
+ public void setSketchbookFolder(File folder) {
+ sketchbookFolder = folder;
+ Preferences.setSketchbookPath(folder.getAbsolutePath());
+ rebuildSketchbookMenus();
+ makeSketchbookSubfolders();
}
- /////////////////////////////////////////////////////////////////////////////
-
-
/**
- * Given a folder, return a list of absolute paths to all jar or zip files
- * inside that folder, separated by pathSeparatorChar.
- *
- * This will prepend a colon (or whatever the path separator is)
- * so that it can be directly appended to another path string.
- *
- * As of 0136, this will no longer add the root folder as well.
- *
- * This function doesn't bother checking to see if there are any .class
- * files in the folder or within a subfolder.
+ * Create the libraries, modes, tools, examples folders in the sketchbook.
*/
- static public String contentsToClassPath(File folder) {
- if (folder == null) return "";
-
- StringBuilder sb = new StringBuilder();
- String sep = System.getProperty("path.separator");
-
- try {
- String path = folder.getCanonicalPath();
-
- // When getting the name of this folder, make sure it has a slash
- // after it, so that the names of sub-items can be added.
- if (!path.endsWith(File.separator)) {
- path += File.separator;
- }
-
- String list[] = folder.list();
- for (int i = 0; i < list.length; i++) {
- // Skip . and ._ files. Prior to 0125p3, .jar files that had
- // OS X AppleDouble files associated would cause trouble.
- if (list[i].startsWith(".")) continue;
-
- if (list[i].toLowerCase().endsWith(".jar") ||
- list[i].toLowerCase().endsWith(".zip")) {
- sb.append(sep);
- sb.append(path);
- sb.append(list[i]);
- }
- }
- } catch (IOException e) {
- e.printStackTrace(); // this would be odd
- }
- return sb.toString();
+ static protected void makeSketchbookSubfolders() {
+ getSketchbookLibrariesFolder().mkdirs();
+ getSketchbookToolsFolder().mkdirs();
+ getSketchbookModesFolder().mkdirs();
+ getSketchbookExamplesFolder().mkdirs();
+ getSketchbookTemplatesFolder().mkdirs();
}
- /**
- * A classpath, separated by the path separator, will contain
- * a series of .jar/.zip files or directories containing .class
- * files, or containing subdirectories that have .class files.
- *
- * @param path the input classpath
- * @return array of possible package names
- */
- static public String[] packageListFromClassPath(String path) {
- Map map = new HashMap();
- String pieces[] =
- PApplet.split(path, File.pathSeparatorChar);
-
- for (int i = 0; i < pieces.length; i++) {
- //System.out.println("checking piece '" + pieces[i] + "'");
- if (pieces[i].length() == 0) continue;
-
- if (pieces[i].toLowerCase().endsWith(".jar") ||
- pieces[i].toLowerCase().endsWith(".zip")) {
- //System.out.println("checking " + pieces[i]);
- packageListFromZip(pieces[i], map);
-
- } else { // it's another type of file or directory
- File dir = new File(pieces[i]);
- if (dir.exists() && dir.isDirectory()) {
- packageListFromFolder(dir, null, map);
- //importCount = magicImportsRecursive(dir, null,
- // map);
- //imports, importCount);
- }
- }
- }
- int mapCount = map.size();
- String output[] = new String[mapCount];
- int index = 0;
- Set set = map.keySet();
- for (String s : set) {
- output[index++] = s.replace('/', '.');
- }
- //System.arraycopy(imports, 0, output, 0, importCount);
- //PApplet.printarr(output);
- return output;
+ static public File getSketchbookFolder() {
+ return sketchbookFolder;
}
- static private void packageListFromZip(String filename, Map map) {
- try {
- ZipFile file = new ZipFile(filename);
- Enumeration entries = file.entries();
- while (entries.hasMoreElements()) {
- ZipEntry entry = (ZipEntry) entries.nextElement();
-
- if (!entry.isDirectory()) {
- String name = entry.getName();
-
- if (name.endsWith(".class")) {
- int slash = name.lastIndexOf('/');
- if (slash == -1) continue;
-
- String pname = name.substring(0, slash);
- if (map.get(pname) == null) {
- map.put(pname, new Object());
- }
- }
- }
- }
- file.close();
- } catch (IOException e) {
- System.err.println("Ignoring " + filename + " (" + e.getMessage() + ")");
- //e.printStackTrace();
- }
+ static public File getSketchbookLibrariesFolder() {
+ return new File(sketchbookFolder, "libraries");
}
- /**
- * Make list of package names by traversing a directory hierarchy.
- * Each time a class is found in a folder, add its containing set
- * of folders to the package list. If another folder is found,
- * walk down into that folder and continue.
- */
- static private void packageListFromFolder(File dir, String sofar,
- Map map) {
- //String imports[],
- //int importCount) {
- //System.err.println("checking dir '" + dir + "'");
- boolean foundClass = false;
- String files[] = dir.list();
-
- for (int i = 0; i < files.length; i++) {
- if (files[i].equals(".") || files[i].equals("..")) continue;
-
- File sub = new File(dir, files[i]);
- if (sub.isDirectory()) {
- String nowfar =
- (sofar == null) ? files[i] : (sofar + "." + files[i]);
- packageListFromFolder(sub, nowfar, map);
- //System.out.println(nowfar);
- //imports[importCount++] = nowfar;
- //importCount = magicImportsRecursive(sub, nowfar,
- // imports, importCount);
- } else if (!foundClass) { // if no classes found in this folder yet
- if (files[i].endsWith(".class")) {
- //System.out.println("unique class: " + files[i] + " for " + sofar);
- map.put(sofar, new Object());
- foundClass = true;
- }
- }
- }
+ static public File getSketchbookToolsFolder() {
+ return new File(sketchbookFolder, "tools");
}
- static public void unzip(File zipFile, File dest) {
- try {
- FileInputStream fis = new FileInputStream(zipFile);
- CheckedInputStream checksum = new CheckedInputStream(fis, new Adler32());
- ZipInputStream zis = new ZipInputStream(new BufferedInputStream(checksum));
- ZipEntry next = null;
- while ((next = zis.getNextEntry()) != null) {
- File currentFile = new File(dest, next.getName());
- if (next.isDirectory()) {
- currentFile.mkdirs();
- } else {
- File parentDir = currentFile.getParentFile();
- // Sometimes the directory entries aren't already created
- if (!parentDir.exists()) {
- parentDir.mkdirs();
- }
- currentFile.createNewFile();
- unzipEntry(zis, currentFile);
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
+ static public File getSketchbookModesFolder() {
+ return new File(sketchbookFolder, "modes");
}
- static protected void unzipEntry(ZipInputStream zin, File f) throws IOException {
- FileOutputStream out = new FileOutputStream(f);
- byte[] b = new byte[512];
- int len = 0;
- while ((len = zin.read(b)) != -1) {
- out.write(b, 0, len);
- }
- out.flush();
- out.close();
+ static public File getSketchbookExamplesFolder() {
+ return new File(sketchbookFolder, "examples");
}
- static public void log(Object from, String message) {
- if (DEBUG) {
- System.out.println(from.getClass().getName() + ": " + message);
- }
+ static public File getSketchbookTemplatesFolder() {
+ return new File(sketchbookFolder, "templates");
}
- static public void log(String message) {
- if (DEBUG) {
- System.out.println(message);
- }
- }
-
+ static protected File getDefaultSketchbookFolder() {
+ File sketchbookFolder = null;
+ try {
+ sketchbookFolder = Platform.getDefaultSketchbookFolder();
+ } catch (Exception e) { }
- static public void logf(String message, Object... args) {
- if (DEBUG) {
- System.out.println(String.format(message, args));
+ if (sketchbookFolder == null) {
+ Messages.showError("No sketchbook",
+ "Problem while trying to get the sketchbook", null);
}
- }
+ // create the folder if it doesn't exist already
+ boolean result = true;
+ if (!sketchbookFolder.exists()) {
+ result = sketchbookFolder.mkdirs();
+ }
- static public void log(String message, Throwable e) {
- if (DEBUG) {
- System.out.println(message);
- e.printStackTrace();
+ if (!result) {
+ Messages.showError("You forgot your sketchbook",
+ "Processing cannot run because it could not\n" +
+ "create a folder to store your sketchbook.", null);
}
+
+ return sketchbookFolder;
}
}
diff --git a/app/src/processing/app/BaseSplash.java b/app/src/processing/app/BaseSplash.java
new file mode 100644
index 0000000000..5dc125f6a1
--- /dev/null
+++ b/app/src/processing/app/BaseSplash.java
@@ -0,0 +1,24 @@
+package processing.app;
+
+import java.io.File;
+
+import processing.app.ui.SplashWindow;
+import processing.app.ui.Toolkit;
+
+
+public class BaseSplash {
+ static public void main(String[] args) {
+ try {
+ final boolean hidpi = Toolkit.highResImages();
+ final String filename = "lib/about-" + (hidpi ? 2 : 1) + "x.png";
+ File splashFile = Platform.getContentFile(filename);
+ SplashWindow.splash(splashFile.toURI().toURL(), hidpi);
+ SplashWindow.invokeMain("processing.app.Base", args);
+ SplashWindow.disposeSplash();
+ } catch (Exception e) {
+ e.printStackTrace();
+ // !@#!@$$! umm
+ //SplashWindow.invokeMain("processing.app.Base", args);
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/processing/app/Console.java b/app/src/processing/app/Console.java
new file mode 100644
index 0000000000..73b652f337
--- /dev/null
+++ b/app/src/processing/app/Console.java
@@ -0,0 +1,261 @@
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+/*
+ Part of the Processing project - http://processing.org
+
+ Copyright (c) 2012-16 The Processing Foundation
+ Copyright (c) 2004-12 Ben Fry and Casey Reas
+ Copyright (c) 2001-04 Massachusetts Institute of Technology
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+package processing.app;
+
+import java.io.*;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+
+/**
+ * Non-GUI handling of System.out and System.err redirection.
+ *
+ * Be careful when debugging this class, because if it's throwing exceptions,
+ * don't take over System.err, and debug while watching just System.out
+ * or just call println() or whatever directly to systemOut or systemErr.
+ *
+ * Also note that encodings will not work properly when run from Eclipse. This
+ * means that if you use non-ASCII characters in a println() or some such,
+ * the characters won't print properly in the Processing and/or Eclipse console.
+ * It seems that Eclipse's console-grabbing and that of Processing don't
+ * get along with one another. Use 'ant run' to work on encoding-related issues.
+ */
+public class Console {
+ // Single static instance shared because there's only one real System.out.
+ // Within the input handlers, the currentConsole variable will be used to
+ // echo things to the correct location.
+
+ /** The original System.out */
+ static PrintStream systemOut;
+ /** The original System.err */
+ static PrintStream systemErr;
+
+ /** Our replacement System.out */
+ static PrintStream consoleOut;
+ /** Our replacement System.err */
+ static PrintStream consoleErr;
+
+ /** All stdout also written to a file */
+ static OutputStream stdoutFile;
+ /** All stderr also written to a file */
+ static OutputStream stderrFile;
+
+ /** stdout listener for the currently active Editor */
+ static OutputStream editorOut;
+ /** stderr listener for the currently active Editor */
+ static OutputStream editorErr;
+
+
+ static public void startup() {
+ if (systemOut != null) {
+ // TODO fix this dreadful style choice in how the Console is initialized
+ // (This is not good code.. startup() should gracefully deal with this.
+ // It's just a low priority relative to the likelihood of trouble.)
+ new Exception("startup() called more than once").printStackTrace(systemErr);
+ return;
+ }
+ systemOut = System.out;
+ systemErr = System.err;
+
+ // placing everything inside a try block because this can be a dangerous
+ // time for the lights to blink out and crash for and obscure reason.
+ try {
+ SimpleDateFormat formatter = new SimpleDateFormat("yyMMdd_HHmmss");
+ // Moving away from a random string in 0256 (and adding hms) because
+ // the random digits looked like times anyway, causing confusion.
+ //String randy = String.format("%04d", (int) (1000 * Math.random()));
+ //final String stamp = formatter.format(new Date()) + "_" + randy;
+ final String stamp = formatter.format(new Date());
+
+ File consoleDir = Base.getSettingsFile("console");
+ if (consoleDir.exists()) {
+ // clear old debug files
+ File[] stdFiles = consoleDir.listFiles(new FileFilter() {
+ final String todayPrefix = stamp.substring(0, 4);
+
+ public boolean accept(File file) {
+ if (!file.isDirectory()) {
+ String name = file.getName();
+ if (name.endsWith(".err") || name.endsWith(".out")) {
+ // don't delete any of today's debug messages
+ return !name.startsWith(todayPrefix);
+ }
+ }
+ return false;
+ }
+ });
+ // Remove any files that aren't from today
+ for (File file : stdFiles) {
+ file.delete();
+ }
+ } else {
+ consoleDir.mkdirs();
+ consoleDir.setWritable(true, false);
+ }
+
+ File outFile = new File(consoleDir, stamp + ".out");
+ outFile.setWritable(true, false);
+ stdoutFile = new FileOutputStream(outFile);
+ File errFile = new File(consoleDir, stamp + ".err");
+ errFile.setWritable(true, false);
+ stderrFile = new FileOutputStream(errFile);
+
+ consoleOut = new PrintStream(new ConsoleStream(false));
+ consoleErr = new PrintStream(new ConsoleStream(true));
+
+ System.setOut(consoleOut);
+ System.setErr(consoleErr);
+
+ } catch (Exception e) {
+ stdoutFile = null;
+ stderrFile = null;
+
+ consoleOut = null;
+ consoleErr = null;
+
+ System.setOut(systemOut);
+ System.setErr(systemErr);
+
+ e.printStackTrace();
+ }
+ }
+
+
+ static public void setEditor(OutputStream out, OutputStream err) {
+ editorOut = out;
+ editorErr = err;
+ }
+
+
+ static public void systemOut(String what) {
+ systemOut.println(what);
+ }
+
+
+ static public void systemErr(String what) {
+ systemErr.println(what);
+ }
+
+
+ /**
+ * Close the streams so that the temporary files can be deleted.
+ *
+ * File.deleteOnExit() cannot be used because the stdout and stderr
+ * files are inside a folder, and have to be deleted before the
+ * folder itself is deleted, which can't be guaranteed when using
+ * the deleteOnExit() method.
+ */
+ static public void shutdown() {
+ // replace original streams to remove references to console's streams
+ System.setOut(systemOut);
+ System.setErr(systemErr);
+
+ cleanup(consoleOut);
+ cleanup(consoleErr);
+
+ // also have to close the original FileOutputStream
+ // otherwise it won't be shut down completely
+ cleanup(stdoutFile);
+ cleanup(stderrFile);
+ }
+
+
+ static private void cleanup(OutputStream output) {
+ try {
+ if (output != null) {
+ output.flush();
+ output.close();
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+
+
+ static class ConsoleStream extends OutputStream {
+ boolean err; // whether stderr or stdout
+ byte single[] = new byte[1];
+
+ public ConsoleStream(boolean err) {
+ this.err = err;
+ }
+
+ public void close() { }
+
+ public void flush() { }
+
+ public void write(byte b[]) { // appears never to be used
+ write(b, 0, b.length);
+ }
+
+ public void write(byte b[], int offset, int length) {
+ // First write to the original stdout/stderr
+ if (err) {
+ systemErr.write(b, offset, length);
+ } else {
+ systemOut.write(b, offset, length);
+ }
+
+ // Write to the files that are storing this information
+ writeFile(b, offset, length);
+
+ // Write to the console of the current Editor, if any
+ try {
+ if (err) {
+ if (editorErr != null) {
+ editorErr.write(b, offset, length);
+ }
+ } else {
+ if (editorOut != null) {
+ editorOut.write(b, offset, length);
+ }
+ }
+ } catch (IOException e) {
+ // Avoid this function being called in a recursive, infinite loop
+ e.printStackTrace(systemErr);
+ }
+ }
+
+ public void writeFile(byte b[], int offset, int length) {
+ final OutputStream echo = err ? stderrFile : stdoutFile;
+ if (echo != null) {
+ try {
+ echo.write(b, offset, length);
+ echo.flush();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public void write(int b) {
+ single[0] = (byte) b;
+ write(single, 0, 1);
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java
deleted file mode 100644
index 87311016ec..0000000000
--- a/app/src/processing/app/Editor.java
+++ /dev/null
@@ -1,2949 +0,0 @@
-/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
-
-/*
- Part of the Processing project - http://processing.org
-
- Copyright (c) 2012-14 The Processing Foundation
- Copyright (c) 2004-12 Ben Fry and Casey Reas
- Copyright (c) 2001-04 Massachusetts Institute of Technology
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2
- as published by the Free Software Foundation.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software Foundation,
- Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-package processing.app;
-
-import processing.app.contrib.ToolContribution;
-import processing.app.syntax.*;
-import processing.app.tools.*;
-import processing.core.*;
-
-import java.awt.*;
-import java.awt.datatransfer.*;
-import java.awt.event.*;
-import java.awt.print.*;
-import java.io.*;
-import java.nio.file.*;
-import java.util.*;
-import java.util.List;
-import java.util.Timer;
-
-import javax.swing.*;
-import javax.swing.event.*;
-import javax.swing.text.*;
-import javax.swing.undo.*;
-
-/**
- * Main editor panel for the Processing Development Environment.
- */
-public abstract class Editor extends JFrame implements RunnerListener {
- protected Base base;
- protected EditorState state;
- protected Mode mode;
-
- // otherwise, if the window is resized with the message label
- // set to blank, it's preferredSize() will be fukered
- static protected final String EMPTY =
- " " +
- " " +
- " ";
-
- /**
- * true if this file has not yet been given a name by the user
- */
-// private boolean untitled;
-
- private PageFormat pageFormat;
- private PrinterJob printerJob;
-
- // file and sketch menus for re-inserting items
- private JMenu fileMenu;
-// private JMenuItem saveMenuItem;
-// private JMenuItem saveAsMenuItem;
-
- private JMenu sketchMenu;
-
- protected EditorHeader header;
- protected EditorToolbar toolbar;
- protected JEditTextArea textarea;
- protected EditorStatus status;
- protected JSplitPane splitPane;
- protected JPanel consolePanel;
- protected EditorConsole console;
- protected EditorLineStatus lineStatus;
-
- // currently opened program
- protected Sketch sketch;
-
- // runtime information and window placement
- private Point sketchWindowLocation;
-
- // undo fellers
- private JMenuItem undoItem, redoItem;
- protected UndoAction undoAction;
- protected RedoAction redoAction;
- /** the currently selected tab's undo manager */
- private UndoManager undo;
- // used internally for every edit. Groups hotkey-event text manipulations and
- // groups multi-character inputs into a single undos.
- private CompoundEdit compoundEdit;
- // timer to decide when to group characters into an undo
- private Timer timer;
- private TimerTask endUndoEvent;
- // true if inserting text, false if removing text
- private boolean isInserting;
- // maintain caret position during undo operations
- private final Stack caretUndoStack = new Stack();
- private final Stack caretRedoStack = new Stack();
-
- private FindReplace find;
- JMenu toolsMenu;
- JMenu modeMenu;
-
- ArrayList coreTools;
- public ArrayList contribTools;
-
-
-// protected Editor(final Base base, String path, int[] location, final Mode mode) {
- protected Editor(final Base base, String path, EditorState state, final Mode mode) {
- super("Processing", state.checkConfig());
- this.base = base;
- this.state = state;
- this.mode = mode;
-
- Toolkit.setIcon(this); // TODO should this be per-mode?
-
- // Install default actions for Run, Present, etc.
-// resetHandlers();
-
- // add listener to handle window close box hit event
- addWindowListener(new WindowAdapter() {
- public void windowClosing(WindowEvent e) {
- base.handleClose(Editor.this, false);
- }
- });
- // don't close the window when clicked, the app will take care
- // of that via the handleQuitInternal() methods
- // http://dev.processing.org/bugs/show_bug.cgi?id=440
- setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
-
- // When bringing a window to front, let the Base know
- addWindowListener(new WindowAdapter() {
- public void windowActivated(WindowEvent e) {
-// EditorConsole.systemOut.println("editor window activated");
- base.handleActivated(Editor.this);
-// mode.handleActivated(Editor.this);
-// fileMenu.insert(base.getSketchbookMenu(), 2);
- fileMenu.insert(base.getRecentMenu(), 2);
-// fileMenu.insert(mode.getExamplesMenu(), 3);
- sketchMenu.insert(mode.getImportMenu(), 4);
- mode.insertToolbarRecentMenu();
- }
-
- // added for 1.0.5
- // http://dev.processing.org/bugs/show_bug.cgi?id=1260
- public void windowDeactivated(WindowEvent e) {
-// EditorConsole.systemErr.println("editor window deactivated");
-// mode.handleDeactivated(Editor.this);
-// fileMenu.remove(base.getSketchbookMenu());
- fileMenu.remove(base.getRecentMenu());
-// fileMenu.remove(mode.getExamplesMenu());
- sketchMenu.remove(mode.getImportMenu());
- mode.removeToolbarRecentMenu();
- }
- });
-
- timer = new Timer();
-
- buildMenuBar();
-
- Container contentPain = getContentPane();
- contentPain.setLayout(new BorderLayout());
- JPanel pain = new JPanel();
- pain.setLayout(new BorderLayout());
- contentPain.add(pain, BorderLayout.CENTER);
-
- Box box = Box.createVerticalBox();
- Box upper = Box.createVerticalBox();
-
- initModeMenu();
- toolbar = createToolbar();
- upper.add(toolbar);
-
- header = new EditorHeader(this);
- upper.add(header);
-
- textarea = createTextArea();
- textarea.setRightClickPopup(new TextAreaPopup());
- textarea.setHorizontalOffset(JEditTextArea.leftHandGutter);
-
- // assemble console panel, consisting of status area and the console itself
- consolePanel = new JPanel();
- consolePanel.setLayout(new BorderLayout());
-
- status = new EditorStatus(this);
- consolePanel.add(status, BorderLayout.NORTH);
-
- console = new EditorConsole(this);
- // windows puts an ugly border on this guy
- console.setBorder(null);
- consolePanel.add(console, BorderLayout.CENTER);
-
- lineStatus = new EditorLineStatus(this);
- consolePanel.add(lineStatus, BorderLayout.SOUTH);
-
- upper.add(textarea);
-
- // alternate spot for status, but ugly
-// status = new EditorStatus(this);
-// upper.add(status);
-
- splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, upper, consolePanel);
-
- // disable this because it hides the message area, which is essential (issue #745)
- splitPane.setOneTouchExpandable(false);
- // repaint child panes while resizing
- splitPane.setContinuousLayout(true);
- // if window increases in size, give all of increase to
- // the textarea in the upper pane
- splitPane.setResizeWeight(1D);
-
- // to fix ugliness.. normally macosx java 1.3 puts an
- // ugly white border around this object, so turn it off.
- splitPane.setBorder(null);
-
- // the default size on windows is too small and kinda ugly
- int dividerSize = Preferences.getInteger("editor.divider.size");
- if (dividerSize != 0) {
- splitPane.setDividerSize(dividerSize);
- }
-
- box.add(splitPane);
-
- pain.add(box);
-
- // get shift down/up events so we can show the alt version of toolbar buttons
- textarea.addKeyListener(toolbar);
-
- // end an undo-chunk any time the caret moves unless it's when text is edited
- textarea.addCaretListener(new CaretListener() {
- String lastText = textarea.getText();
- public void caretUpdate(CaretEvent e) {
- String newText = textarea.getText();
- if (lastText.equals(newText) && isDirectEdit()) {
- endTextEditHistory();
- }
- lastText = newText;
- }
- });
-
- pain.setTransferHandler(new FileDropHandler());
-
- // Finish preparing Editor (formerly found in Base)
- pack();
-
- // Set the window bounds and the divider location before setting it visible
- state.apply(this);
-
- // Set the minimum size for the editor window
- setMinimumSize(new Dimension(Preferences.getInteger("editor.window.width.min"),
- Preferences.getInteger("editor.window.height.min")));
-
- // Bring back the general options for the editor
- applyPreferences();
-
- // Make textField get the focus whenever frame is activated.
- // http://download.oracle.com/javase/tutorial/uiswing/misc/focus.html
- // May not be necessary, but helps avoid random situations with
- // the editor not being able to request its own focus.
- addWindowFocusListener(new WindowAdapter() {
- public void windowGainedFocus(WindowEvent e) {
- textarea.requestFocusInWindow();
- }
-
-// public void windowLostFocus(WindowEvent e) {
-// System.out.println("lost focus, should we tell the text area?");
-// }
- });
-
- // Open the document that was passed in
- boolean loaded = handleOpenInternal(path);
- if (!loaded) {
- sketch = null;
- }
- }
-
-
- /**
- * Broken out to get modes working for GSOC, but this needs a longer-term
- * solution where the listeners are handled properly.
- */
- protected JEditTextArea createTextArea() {
- return new JEditTextArea(new PdeTextAreaDefaults(mode));
- }
-
-
- public EditorState getEditorState() {
- return state;
- }
-
-
- public void removeRecent() {
- base.removeRecent(this);
- }
-
-
- public void addRecent() {
- base.handleRecent(this);
- }
-
-
- /**
- * Handles files dragged & dropped from the desktop and into the editor
- * window. Dragging files into the editor window is the same as using
- * "Sketch → Add File" for each file.
- */
- class FileDropHandler extends TransferHandler {
- public boolean canImport(TransferHandler.TransferSupport support) {
- return !sketch.isReadOnly();
- }
-
- @SuppressWarnings("unchecked")
- public boolean importData(TransferHandler.TransferSupport support) {
- int successful = 0;
-
- if (!canImport(support)) {
- return false;
- }
-
- try {
- Transferable transferable = support.getTransferable();
- DataFlavor uriListFlavor =
- new DataFlavor("text/uri-list;class=java.lang.String");
-
- if (transferable.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
- java.util.List list = (java.util.List)
- transferable.getTransferData(DataFlavor.javaFileListFlavor);
- for (int i = 0; i < list.size(); i++) {
- File file = (File) list.get(i);
- if (sketch.addFile(file)) {
- successful++;
- }
- }
- } else if (transferable.isDataFlavorSupported(uriListFlavor)) {
- // Some platforms (Mac OS X and Linux, when this began) preferred
- // this method of moving files.
- String data = (String)transferable.getTransferData(uriListFlavor);
- String[] pieces = PApplet.splitTokens(data, "\r\n");
- for (int i = 0; i < pieces.length; i++) {
- if (pieces[i].startsWith("#")) continue;
-
- String path = null;
- if (pieces[i].startsWith("file:///")) {
- path = pieces[i].substring(7);
- } else if (pieces[i].startsWith("file:/")) {
- path = pieces[i].substring(5);
- }
- if (sketch.addFile(new File(path))) {
- successful++;
- }
- }
- }
- } catch (Exception e) {
- Base.showWarning("Drag & Drop Problem",
- "An error occurred while trying to add files to the sketch.", e);
- return false;
- }
-
- statusNotice(Language.pluralize("editor.status.drag_and_drop.files_added", successful));
-
- return true;
- }
- }
-
-
- public Base getBase() {
- return base;
- }
-
-
- public Mode getMode() {
- return mode;
- }
-
-
- protected void initModeMenu() {
- modeMenu = new JMenu();
- ButtonGroup modeGroup = new ButtonGroup();
- for (final Mode m : base.getModeList()) {
- JRadioButtonMenuItem item = new JRadioButtonMenuItem(m.getTitle());
- item.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- if (!sketch.isModified()) {
- base.changeMode(m);
-
- } else {
- Base.showWarning("Save",
- "Please save the sketch before changing the mode.",
- null);
-
- // Re-select the old checkbox, because it was automatically
- // updated by Java, even though the Mode could not be changed.
- // https://github.com/processing/processing/issues/2615
- for (Component c : modeMenu.getPopupMenu().getComponents()) {
- if (c instanceof JRadioButtonMenuItem) {
- if (((JRadioButtonMenuItem)c).getText() == mode.getTitle()) {
- ((JRadioButtonMenuItem)c).setSelected(true);
- break;
- }
- }
- }
- }
- }
- });
- modeMenu.add(item);
- modeGroup.add(item);
- if (mode == m) {
- item.setSelected(true);
- }
- }
-
- modeMenu.addSeparator();
- JMenuItem addLib = new JMenuItem(Language.text("toolbar.add_mode"));
- addLib.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- base.handleOpenModeManager();
- }
- });
- modeMenu.add(addLib);
- }
-
-
- public void rebuildModeMenu() {
- initModeMenu();
- }
-
-
- public JMenu getModeMenu() {
- return modeMenu;
- }
-
-
-
-// public Settings getTheme() {
-// return mode.getTheme();
-// }
-
-
- abstract public EditorToolbar createToolbar();
-
-
- abstract public Formatter createFormatter();
-
-
-// protected void setPlacement(int[] location) {
-// setBounds(location[0], location[1], location[2], location[3]);
-// if (location[4] != 0) {
-// splitPane.setDividerLocation(location[4]);
-// }
-// }
-//
-//
-// protected int[] getPlacement() {
-// int[] location = new int[5];
-//
-// // Get the dimensions of the Frame
-// Rectangle bounds = getBounds();
-// location[0] = bounds.x;
-// location[1] = bounds.y;
-// location[2] = bounds.width;
-// location[3] = bounds.height;
-//
-// // Get the current placement of the divider
-// location[4] = splitPane.getDividerLocation();
-//
-// return location;
-// }
-
-
- protected void setDividerLocation(int pos) {
- splitPane.setDividerLocation(pos);
- }
-
-
- protected int getDividerLocation() {
- return splitPane.getDividerLocation();
- }
-
-
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
-
-
- /**
- * Read and apply new values from the preferences, either because
- * the app is just starting up, or the user just finished messing
- * with things in the Preferences window.
- */
- protected void applyPreferences() {
- // Update fonts and other items controllable from the prefs
- textarea.getPainter().updateAppearance();
- textarea.repaint();
-
- console.updateAppearance();
-
- // All of this code was specific to using an external editor.
- /*
-// // apply the setting for 'use external editor'
-// boolean external = Preferences.getBoolean("editor.external");
-// textarea.setEditable(!external);
-// saveMenuItem.setEnabled(!external);
-// saveAsMenuItem.setEnabled(!external);
-
- TextAreaPainter painter = textarea.getPainter();
-// if (external) {
-// // disable line highlight and turn off the caret when disabling
-// Color color = mode.getColor("editor.external.bgcolor");
-// painter.setBackground(color);
-// painter.setLineHighlightEnabled(false);
-// textarea.setCaretVisible(false);
-// } else {
- Color color = mode.getColor("editor.bgcolor");
- painter.setBackground(color);
- boolean highlight = Preferences.getBoolean("editor.linehighlight");
- painter.setLineHighlightEnabled(highlight);
- textarea.setCaretVisible(true);
-// }
-
- // apply changes to the font size for the editor
-// painter.setFont(Preferences.getFont("editor.font"));
-
- // in case tab expansion stuff has changed
- // removing this, just checking prefs directly instead
-// listener.applyPreferences();
-
- // in case moved to a new location
- // For 0125, changing to async version (to be implemented later)
- //sketchbook.rebuildMenus();
- // For 0126, moved into Base, which will notify all editors.
- //base.rebuildMenusAsync();
- */
- }
-
-
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
-
-
- protected void buildMenuBar() {
- JMenuBar menubar = new JMenuBar();
- menubar = new JMenuBar();
- fileMenu = buildFileMenu();
- menubar.add(fileMenu);
- menubar.add(buildEditMenu());
- menubar.add(buildSketchMenu());
-
- // For 3.0a4 move mode menu to the left of the Tool menu
- JMenu modeMenu = buildModeMenu();
- if (modeMenu != null) {
- menubar.add(modeMenu);
- }
-
- rebuildToolMenu();
- menubar.add(getToolMenu());
-
- menubar.add(buildHelpMenu());
- setJMenuBar(menubar);
- }
-
-
- abstract public JMenu buildFileMenu();
-
-
-// public JMenu buildFileMenu(Editor editor) {
-// return buildFileMenu(editor, null);
-// }
-//
-//
-// // most of these items are per-mode
-// protected JMenu buildFileMenu(Editor editor, JMenuItem[] exportItems) {
-
-
- protected JMenu buildFileMenu(JMenuItem[] exportItems) {
- JMenuItem item;
- JMenu fileMenu = new JMenu(Language.text("menu.file"));
-
- item = Toolkit.newJMenuItem(Language.text("menu.file.new"), 'N');
- item.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- base.handleNew();
- }
- });
- fileMenu.add(item);
-
- item = Toolkit.newJMenuItem(Language.text("menu.file.open"), 'O');
- item.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- base.handleOpenPrompt();
- }
- });
- fileMenu.add(item);
-
-// fileMenu.add(base.getSketchbookMenu());
-
- item = Toolkit.newJMenuItemShift(Language.text("menu.file.sketchbook"), 'K');
- item.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- mode.showSketchbookFrame();
- }
- });
- fileMenu.add(item);
-
- item = Toolkit.newJMenuItemShift(Language.text("menu.file.examples"), 'O');
- item.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- mode.showExamplesFrame();
- }
- });
- fileMenu.add(item);
-
- item = Toolkit.newJMenuItem(Language.text("menu.file.close"), 'W');
- item.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- base.handleClose(Editor.this, false);
- }
- });
- fileMenu.add(item);
-
- item = Toolkit.newJMenuItem(Language.text("menu.file.save"), 'S');
- item.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- handleSave(false);
- }
- });
-// saveMenuItem = item;
- fileMenu.add(item);
-
- item = Toolkit.newJMenuItemShift(Language.text("menu.file.save_as"), 'S');
- item.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- handleSaveAs();
- }
- });
-// saveAsMenuItem = item;
- fileMenu.add(item);
-
- if (exportItems != null) {
- for (JMenuItem ei : exportItems) {
- fileMenu.add(ei);
- }
- }
- fileMenu.addSeparator();
-
- item = Toolkit.newJMenuItemShift(Language.text("menu.file.page_setup"), 'P');
- item.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- handlePageSetup();
- }
- });
- fileMenu.add(item);
-
- item = Toolkit.newJMenuItem(Language.text("menu.file.print"), 'P');
- item.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- handlePrint();
- }
- });
- fileMenu.add(item);
-
- // Mac OS X already has its own preferences and quit menu.
- // That's right! Think different, b*tches!
- if (!Base.isMacOS()) {
- fileMenu.addSeparator();
-
- item = Toolkit.newJMenuItem(Language.text("menu.file.preferences"), ',');
- item.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- base.handlePrefs();
- }
- });
- fileMenu.add(item);
-
- fileMenu.addSeparator();
-
- item = Toolkit.newJMenuItem(Language.text("menu.file.quit"), 'Q');
- item.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- base.handleQuit();
- }
- });
- fileMenu.add(item);
- }
- return fileMenu;
- }
-
-
-// public void setSaveItem(JMenuItem item) {
-// saveMenuItem = item;
-// }
-
-
-// public void setSaveAsItem(JMenuItem item) {
-// saveAsMenuItem = item;
-// }
-
-
- protected JMenu buildEditMenu() {
- JMenu menu = new JMenu(Language.text("menu.edit"));
- JMenuItem item;
-
- undoItem = Toolkit.newJMenuItem(Language.text("menu.edit.undo"), 'Z');
- undoItem.addActionListener(undoAction = new UndoAction());
- menu.add(undoItem);
-
- // Gotta follow them interface guidelines
- // http://code.google.com/p/processing/issues/detail?id=363
- if (Base.isWindows()) {
- redoItem = Toolkit.newJMenuItem(Language.text("menu.edit.redo"), 'Y');
- } else { // Linux and OS X
- redoItem = Toolkit.newJMenuItemShift(Language.text("menu.edit.redo"), 'Z');
- }
- redoItem.addActionListener(redoAction = new RedoAction());
- menu.add(redoItem);
-
- menu.addSeparator();
-
- // TODO "cut" and "copy" should really only be enabled
- // if some text is currently selected
- item = Toolkit.newJMenuItem(Language.text("menu.edit.cut"), 'X');
- item.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- handleCut();
- }
- });
- menu.add(item);
-
- item = Toolkit.newJMenuItem(Language.text("menu.edit.copy"), 'C');
- item.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- textarea.copy();
- }
- });
- menu.add(item);
-
- item = Toolkit.newJMenuItemShift(Language.text("menu.edit.copy_as_html"), 'C');
- item.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- handleCopyAsHTML();
- }
- });
- menu.add(item);
-
- item = Toolkit.newJMenuItem(Language.text("menu.edit.paste"), 'V');
- item.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- textarea.paste();
- sketch.setModified(true);
- }
- });
- menu.add(item);
-
- item = Toolkit.newJMenuItem(Language.text("menu.edit.select_all"), 'A');
- item.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- textarea.selectAll();
- }
- });
- menu.add(item);
-
- /*
- menu.addSeparator();
-
- item = Toolkit.newJMenuItem("Delete Selected Lines", 'D');
- item.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- handleDeleteLines();
- }
- });
- menu.add(item);
-
- item = new JMenuItem("Move Selected Lines Up");
- item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_UP, Event.ALT_MASK));
- item.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- handleMoveLines(true);
- }
- });
- menu.add(item);
-
- item = new JMenuItem("Move Selected Lines Down");
- item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, Event.ALT_MASK));
- item.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- handleMoveLines(false);
- }
- });
- menu.add(item);
- */
-
- menu.addSeparator();
-
- item = Toolkit.newJMenuItem(Language.text("menu.edit.auto_format"), 'T');
- item.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- handleAutoFormat();
- }
- });
- menu.add(item);
-
- item = Toolkit.newJMenuItem(Language.text("menu.edit.comment_uncomment"), '/');
- item.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- handleCommentUncomment();
- }
- });
- menu.add(item);
-
- item = Toolkit.newJMenuItem("\u2192 "+Language.text("menu.edit.increase_indent"), ']');
- item.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- handleIndentOutdent(true);
- }
- });
- menu.add(item);
-
- item = Toolkit.newJMenuItem("\u2190 "+Language.text("menu.edit.decrease_indent"), '[');
- item.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- handleIndentOutdent(false);
- }
- });
- menu.add(item);
-
- menu.addSeparator();
-
- item = Toolkit.newJMenuItem(Language.text("menu.edit.find"), 'F');
- item.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- if (find == null) {
- find = new FindReplace(Editor.this);
- }
- //new FindReplace(Editor.this).show();
- find.setVisible(true);
- }
- });
- menu.add(item);
-
- // TODO find next should only be enabled after a
- // search has actually taken place
- item = Toolkit.newJMenuItem(Language.text("menu.edit.find_next"), 'G');
- item.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- if (find != null) {
- find.findNext();
- }
- }
- });
- menu.add(item);
-
- item = Toolkit.newJMenuItemShift(Language.text("menu.edit.find_previous"), 'G');
- item.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- if (find != null) {
- find.findPrevious();
- }
- }
- });
- menu.add(item);
-
- // For Arduino and Mac, this should be command-E, but that currently conflicts with Export Applet
- item = Toolkit.newJMenuItemAlt(Language.text("menu.edit.use_selection_for_find"), 'F');
- item.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- if (find == null) {
- find = new FindReplace(Editor.this);
- }
- find.setFindText(getSelectedText());
- }
- });
- menu.add(item);
-
- return menu;
- }
-
-
- abstract public JMenu buildSketchMenu();
-
-
- protected JMenu buildSketchMenu(JMenuItem[] runItems) {
- JMenuItem item;
- sketchMenu = new JMenu(Language.text("menu.sketch"));
-
- for (JMenuItem mi : runItems) {
- sketchMenu.add(mi);
- }
-
- sketchMenu.addSeparator();
-
- sketchMenu.add(mode.getImportMenu());
-
- item = Toolkit.newJMenuItem(Language.text("menu.sketch.show_sketch_folder"), 'K');
- item.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- Base.openFolder(sketch.getFolder());
- }
- });
- sketchMenu.add(item);
- item.setEnabled(Base.openFolderAvailable());
-
- item = new JMenuItem(Language.text("menu.sketch.add_file"));
- item.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- sketch.handleAddFile();
- }
- });
- sketchMenu.add(item);
-
- sketchMenu.addSeparator();
-
-// final Editor editorName = this;
-
- sketchMenu.addMenuListener(new MenuListener() {
- // Menu Listener that populates the menu only when the menu is opened
- List menuList = new ArrayList();
-
- @Override
- public void menuSelected(MenuEvent event) {
- JMenuItem item;
- for (final Editor editor : base.getEditors()) {
- //if (Editor.this.getSketch().getName().trim().contains(editor2.getSketch().getName().trim()))
- if (getSketch().getMainFilePath().equals(editor.getSketch().getMainFilePath())) {
- item = new JCheckBoxMenuItem(editor.getSketch().getName());
- item.setSelected(true);
- } else {
- item = new JMenuItem(editor.getSketch().getName());
- }
- item.setText(editor.getSketch().getName() +
- " (" + editor.getMode().getTitle() + ")");
-
- // Action listener to bring the appropriate sketch in front
- item.addActionListener(new ActionListener() {
-
- @Override
- public void actionPerformed(ActionEvent e) {
- editor.setState(Frame.NORMAL);
- editor.setVisible(true);
- editor.toFront();
- }
- });
- sketchMenu.add(item);
- menuList.add(item);
- }
- }
-
- @Override
- public void menuDeselected(MenuEvent event) {
- for (JMenuItem item : menuList) {
- sketchMenu.remove(item);
- }
- menuList.clear();
- }
-
- @Override
- public void menuCanceled(MenuEvent event) {
- menuDeselected(event);
- }
- });
-
- return sketchMenu;
- }
-
-
- abstract public void handleImportLibrary(String jarPath);
-
-
- public JMenu getToolMenu() {
- if (toolsMenu == null) {
- rebuildToolMenu();
- }
- return toolsMenu;
- }
-
-
-// protected void rebuildToolList() {
-// coreTools = ToolContribution.list(Base.getToolsFolder(), true);
-// contribTools = ToolContribution.list(Base.getSketchbookToolsFolder(), true);
-// }
-
-
- public void rebuildToolMenu() {
- if (toolsMenu == null) {
- toolsMenu = new JMenu(Language.text("menu.tools"));
- } else {
- toolsMenu.removeAll();
- }
-
-// rebuildToolList();
- coreTools = ToolContribution.loadAll(Base.getToolsFolder());
- contribTools = ToolContribution.loadAll(Base.getSketchbookToolsFolder());
-
- addInternalTools(toolsMenu);
- addTools(toolsMenu, coreTools);
- addTools(toolsMenu, contribTools);
-
- toolsMenu.addSeparator();
- JMenuItem item = new JMenuItem(Language.text("menu.tools.add_tool"));
- item.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- base.handleOpenToolManager();
- }
- });
- toolsMenu.add(item);
- }
-
-
- public void clearToolMenu() {
- toolsMenu.removeAll();
- System.gc();
- }
-
-
- public void removeTool() {
- rebuildToolMenu();
- }
-
-
-// /**
-// * Attempt to init or run a Tool from the safety of a try/catch block that
-// * will report errors to the user.
-// * @param tool The Tool object to be inited or run
-// * @param item null to call init(), or the existing JMenuItem for run()
-// * @return
-// */
-// protected boolean safeTool(Tool tool, JMenuItem item) {
-// try {
-// if (item == null) {
-// tool.init(Editor.this);
-// } else {
-// tool.run();
-// }
-// return true;
-//
-// } catch (NoSuchMethodError nsme) {
-// System.out.println("tool is " + tool + " ");
-// statusError("\"" + tool.getMenuTitle() + "\" " +
-// "is not compatible with this version of Processing");
-// nsme.printStackTrace();
-//
-// } catch (Exception ex) {
-// statusError("An error occurred inside \"" + tool.getMenuTitle() + "\"");
-// ex.printStackTrace();
-// }
-// if (item != null) {
-// item.setEnabled(false); // don't you try that again
-// }
-// return false;
-// }
-
-
- void addToolItem(final Tool tool, HashMap toolItems) {
- String title = tool.getMenuTitle();
- final JMenuItem item = new JMenuItem(title);
- item.addActionListener(new ActionListener() {
-
- public void actionPerformed(ActionEvent e) {
- try {
- tool.run();
-
- } catch (NoSuchMethodError nsme) {
- statusError("\"" + tool.getMenuTitle() + "\" is not" +
- "compatible with this version of Processing");
- //nsme.printStackTrace();
- Base.log("Incompatible tool found during tool.run()", nsme);
- item.setEnabled(false);
-
- } catch (Exception ex) {
- statusError("An error occurred inside \"" + tool.getMenuTitle() + "\"");
- ex.printStackTrace();
- item.setEnabled(false);
- }
- }
- });
- //menu.add(item);
- toolItems.put(title, item);
- }
-
-
- protected void addTools(JMenu menu, ArrayList tools) {
- HashMap toolItems = new HashMap();
-
- for (final ToolContribution tool : tools) {
- try {
- tool.init(Editor.this);
- // If init() fails, the item won't be added to the menu
- addToolItem(tool, toolItems);
-
- // With the exceptions, we can't call statusError because the window
- // isn't completely set up yet. Also not gonna pop up a warning because
- // people may still be running different versions of Processing.
- // TODO Once the dust settles on 2.x, change this to Base.showError()
- // and open the Tools folder instead of showing System.err.println().
-
- } catch (NoSuchMethodError nsme) {
- System.err.println("\"" + tool.getMenuTitle() + "\" is not " +
- "compatible with this version of Processing");
- System.err.println("The " + nsme.getMessage() + " method no longer exists.");
- Base.log("Incompatible Tool found during tool.init()", nsme);
-
- } catch (NoClassDefFoundError ncdfe) {
- System.err.println("\"" + tool.getMenuTitle() + "\" is not " +
- "compatible with this version of Processing");
- System.err.println("The " + ncdfe.getMessage() + " class is no longer available.");
- Base.log("Incompatible Tool found during tool.init()", ncdfe);
-
- } catch (Error err) {
- System.err.println("An error occurred inside \"" + tool.getMenuTitle() + "\"");
- err.printStackTrace();
-
- } catch (Exception ex) {
- System.err.println("An exception occurred inside \"" + tool.getMenuTitle() + "\"");
- ex.printStackTrace();
- }
- }
-
- ArrayList toolList = new ArrayList(toolItems.keySet());
- if (toolList.size() > 0) {
- menu.addSeparator();
- Collections.sort(toolList);
- for (String title : toolList) {
- menu.add(toolItems.get(title));
- }
- }
- }
-
-
- /**
- * Override this if you want a special menu for your particular 'mode'.
- */
- public JMenu buildModeMenu() {
- return null;
- }
-
-
- protected void addToolMenuItem(JMenu menu, String className) {
- try {
- Class> toolClass = Class.forName(className);
- final Tool tool = (Tool) toolClass.newInstance();
-
- JMenuItem item = new JMenuItem(tool.getMenuTitle());
-
- tool.init(Editor.this);
-
- item.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- EventQueue.invokeLater(tool);
- }
- });
- menu.add(item);
-// return item;
-
- } catch (Exception e) {
- e.printStackTrace();
-// return null;
- }
- }
-
-
- protected JMenu addInternalTools(JMenu menu) {
-// JMenuItem item;
-// item = createToolMenuItem("processing.app.tools.AutoFormatTool");
-// int modifiers = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
-// item.setAccelerator(KeyStroke.getKeyStroke('T', modifiers));
-// menu.add(item);
-
- addToolMenuItem(menu, "processing.app.tools.CreateFont");
- addToolMenuItem(menu, "processing.app.tools.ColorSelector");
- addToolMenuItem(menu, "processing.app.tools.Archiver");
-
- if (Base.isMacOS()) {
- addToolMenuItem(menu, "processing.app.tools.InstallCommander");
- }
-
- // I think this is no longer needed... It was Mac OS X specific,
- // and they gave up on MacRoman a long time ago.
-// addToolMenuItem(menu, "processing.app.tools.FixEncoding");
-
- // currently commented out
-// if (Base.DEBUG) {
-// addToolMenuItem(menu, "processing.app.tools.ExportExamples");
-// }
-
-// // These are temporary entries while Android mode is being worked out.
-// // The mode will not be in the tools menu, and won't involve a cmd-key
-// if (!Base.RELEASE) {
-// item = createToolMenuItem("processing.app.tools.android.AndroidTool");
-// item.setAccelerator(KeyStroke.getKeyStroke('D', modifiers));
-// menu.add(item);
-// menu.add(createToolMenuItem("processing.app.tools.android.Permissions"));
-// menu.add(createToolMenuItem("processing.app.tools.android.Reset"));
-// }
-
- return menu;
- }
-
-
- /*
- // testing internal web server to serve up docs from a zip file
- item = new JMenuItem("Web Server Test");
- item.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- //WebServer ws = new WebServer();
- SwingUtilities.invokeLater(new Runnable() {
- public void run() {
- try {
- int port = WebServer.launch("/Users/fry/coconut/processing/build/shared/reference.zip");
- Base.openURL("http://127.0.0.1:" + port + "/reference/setup_.html");
-
- } catch (IOException e1) {
- e1.printStackTrace();
- }
- }
- });
- }
- });
- menu.add(item);
- */
-
- /*
- item = new JMenuItem("Browser Test");
- item.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- //Base.openURL("http://processing.org/learning/gettingstarted/");
- //JFrame browserFrame = new JFrame("Browser");
- BrowserStartup bs = new BrowserStartup("jar:file:/Users/fry/coconut/processing/build/shared/reference.zip!/reference/setup_.html");
- bs.initUI();
- bs.launch();
- }
- });
- menu.add(item);
- */
-
-
- abstract public JMenu buildHelpMenu();
-
-
- public void showReference(String filename) {
- File file = new File(mode.getReferenceFolder(), filename);
- try {
- file = file.getCanonicalFile();
- } catch (IOException e) {
- e.printStackTrace();
- }
- // Prepend with file:// and also encode spaces & other characters
- Base.openURL(file.toURI().toString());
- }
-
-
- static public void showChanges() {
- // http://code.google.com/p/processing/issues/detail?id=1520
- if (!Base.isCommandLine()) {
- Base.openURL("http://wiki.processing.org/w/Changes");
- }
- }
-
-
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
-
-
- class UndoAction extends AbstractAction {
- public UndoAction() {
- super(Language.text("menu.edit.undo"));
- this.setEnabled(false);
- }
-
- public void actionPerformed(ActionEvent e) {
- stopCompoundEdit();
-
- try {
- final Integer caret = caretUndoStack.pop();
- caretRedoStack.push(caret);
- textarea.setCaretPosition(caret);
- textarea.scrollToCaret();
- } catch (Exception ignore) {
- }
- try {
- undo.undo();
- } catch (CannotUndoException ex) {
- //System.out.println("Unable to undo: " + ex);
- //ex.printStackTrace();
- }
- updateUndoState();
- redoAction.updateRedoState();
- if (sketch != null) {
- sketch.setModified(!getText().equals(sketch.getCurrentCode().getSavedProgram()));
- }
- }
-
- protected void updateUndoState() {
- if (undo.canUndo() || compoundEdit != null && compoundEdit.isInProgress()) {
- this.setEnabled(true);
- undoItem.setEnabled(true);
- undoItem.setText(undo.getUndoPresentationName());
- putValue(Action.NAME, undo.getUndoPresentationName());
-// if (sketch != null) {
-// sketch.setModified(true); // 0107, removed for 0196
-// }
- } else {
- this.setEnabled(false);
- undoItem.setEnabled(false);
- undoItem.setText(Language.text("menu.edit.undo"));
- putValue(Action.NAME, Language.text("menu.edit.undo"));
-// if (sketch != null) {
-// sketch.setModified(false); // 0107
-// }
- }
- }
- }
-
-
- class RedoAction extends AbstractAction {
- public RedoAction() {
- super(Language.text("menu.edit.redo"));
- this.setEnabled(false);
- }
-
- public void actionPerformed(ActionEvent e) {
- stopCompoundEdit();
-
- try {
- undo.redo();
- } catch (CannotRedoException ex) {
- //System.out.println("Unable to redo: " + ex);
- //ex.printStackTrace();
- }
- try {
- final Integer caret = caretRedoStack.pop();
- caretUndoStack.push(caret);
- textarea.setCaretPosition(caret);
- } catch (Exception ignore) {
- }
- updateRedoState();
- undoAction.updateUndoState();
- if (sketch != null) {
- sketch.setModified(!getText().equals(sketch.getCurrentCode().getSavedProgram()));
- }
- }
-
- protected void updateRedoState() {
- if (undo.canRedo()) {
- redoItem.setEnabled(true);
- redoItem.setText(undo.getRedoPresentationName());
- putValue(Action.NAME, undo.getRedoPresentationName());
- } else {
- this.setEnabled(false);
- redoItem.setEnabled(false);
- redoItem.setText(Language.text("menu.edit.redo"));
- putValue(Action.NAME, Language.text("menu.edit.redo"));
- }
- }
- }
-
-
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
-
-
- // these will be done in a more generic way soon, more like:
- // setHandler("action name", Runnable);
- // but for the time being, working out the kinks of how many things to
- // abstract from the editor in this fashion.
-
-
-// public void setHandlers(Runnable runHandler, Runnable presentHandler,
-// Runnable stopHandler,
-// Runnable exportHandler, Runnable exportAppHandler) {
-// this.runHandler = runHandler;
-// this.presentHandler = presentHandler;
-// this.stopHandler = stopHandler;
-// this.exportHandler = exportHandler;
-// this.exportAppHandler = exportAppHandler;
-// }
-
-
-// public void resetHandlers() {
-// runHandler = new DefaultRunHandler();
-// presentHandler = new DefaultPresentHandler();
-// stopHandler = new DefaultStopHandler();
-// exportHandler = new DefaultExportHandler();
-// exportAppHandler = new DefaultExportAppHandler();
-// }
-
-
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
-
-
- /**
- * Gets the current sketch object.
- */
- public Sketch getSketch() {
- return sketch;
- }
-
-
- /**
- * Get the JEditTextArea object for use (not recommended). This should only
- * be used in obscure cases that really need to hack the internals of the
- * JEditTextArea. Most tools should only interface via the get/set functions
- * found in this class. This will maintain compatibility with future releases,
- * which will not use JEditTextArea.
- */
- public JEditTextArea getTextArea() {
- return textarea;
- }
-
-
- /**
- * Get the contents of the current buffer. Used by the Sketch class.
- */
- public String getText() {
- return textarea.getText();
- }
-
-
- /**
- * Get a range of text from the current buffer.
- */
- public String getText(int start, int stop) {
- return textarea.getText(start, stop - start);
- }
-
-
- /**
- * Replace the entire contents of the front-most tab.
- */
- public void setText(String what) {
- startCompoundEdit();
- textarea.setText(what);
- stopCompoundEdit();
- }
-
-
- public void insertText(String what) {
- startCompoundEdit();
- int caret = getCaretOffset();
- setSelection(caret, caret);
- textarea.setSelectedText(what);
- stopCompoundEdit();
- }
-
-
- /**
- * Called to update the text but not switch to a different set of code
- * (which would affect the undo manager).
- */
-// public void setText2(String what, int start, int stop) {
-// beginCompoundEdit();
-// textarea.setText(what);
-// endCompoundEdit();
-//
-// // make sure that a tool isn't asking for a bad location
-// start = Math.max(0, Math.min(start, textarea.getDocumentLength()));
-// stop = Math.max(0, Math.min(start, textarea.getDocumentLength()));
-// textarea.select(start, stop);
-//
-// textarea.requestFocus(); // get the caret blinking
-// }
-
-
- public String getSelectedText() {
- return textarea.getSelectedText();
- }
-
-
- public void setSelectedText(String what) {
- textarea.setSelectedText(what);
- }
-
-
- public void setSelection(int start, int stop) {
- // make sure that a tool isn't asking for a bad location
- start = PApplet.constrain(start, 0, textarea.getDocumentLength());
- stop = PApplet.constrain(stop, 0, textarea.getDocumentLength());
-
- textarea.select(start, stop);
- }
-
-
- /**
- * Get the position (character offset) of the caret. With text selected,
- * this will be the last character actually selected, no matter the direction
- * of the selection. That is, if the user clicks and drags to select lines
- * 7 up to 4, then the caret position will be somewhere on line four.
- */
- public int getCaretOffset() {
- return textarea.getCaretPosition();
- }
-
-
- /**
- * True if some text is currently selected.
- */
- public boolean isSelectionActive() {
- return textarea.isSelectionActive();
- }
-
-
- /**
- * Get the beginning point of the current selection.
- */
- public int getSelectionStart() {
- return textarea.getSelectionStart();
- }
-
-
- /**
- * Get the end point of the current selection.
- */
- public int getSelectionStop() {
- return textarea.getSelectionStop();
- }
-
-
- /**
- * Get text for a specified line.
- */
- public String getLineText(int line) {
- return textarea.getLineText(line);
- }
-
-
- /**
- * Replace the text on a specified line.
- */
- public void setLineText(int line, String what) {
- startCompoundEdit();
- textarea.select(getLineStartOffset(line), getLineStopOffset(line));
- textarea.setSelectedText(what);
- stopCompoundEdit();
- }
-
-
- /**
- * Get character offset for the start of a given line of text.
- */
- public int getLineStartOffset(int line) {
- return textarea.getLineStartOffset(line);
- }
-
-
- /**
- * Get character offset for end of a given line of text.
- */
- public int getLineStopOffset(int line) {
- return textarea.getLineStopOffset(line);
- }
-
-
- /**
- * Get the number of lines in the currently displayed buffer.
- */
- public int getLineCount() {
- return textarea.getLineCount();
- }
-
-
- /**
- * Use before a manipulating text to group editing operations together as a
- * single undo. Use stopCompoundEdit() once finished.
- */
- public void startCompoundEdit() {
- stopCompoundEdit();
- compoundEdit = new CompoundEdit();
- }
-
-
- /**
- * Use with startCompoundEdit() to group edit operations in a single undo.
- */
- public void stopCompoundEdit() {
- if (compoundEdit != null) {
- compoundEdit.end();
- undo.addEdit(compoundEdit);
- caretUndoStack.push(textarea.getCaretPosition());
- caretRedoStack.clear();
- undoAction.updateUndoState();
- redoAction.updateRedoState();
- compoundEdit = null;
- }
- }
-
-
- public int getScrollPosition() {
- return textarea.getVerticalScrollPosition();
- }
-
-
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
-
-
- /**
- * Switch between tabs, this swaps out the Document object
- * that's currently being manipulated.
- */
- protected void setCode(SketchCode code) {
- SyntaxDocument document = (SyntaxDocument) code.getDocument();
-
- if (document == null) { // this document not yet inited
- document = new SyntaxDocument();
- code.setDocument(document);
-
- // turn on syntax highlighting
- document.setTokenMarker(mode.getTokenMarker());
-
- // insert the program text into the document object
- try {
- document.insertString(0, code.getProgram(), null);
- } catch (BadLocationException bl) {
- bl.printStackTrace();
- }
-
- // set up this guy's own undo manager
-// code.undo = new UndoManager();
-
- document.addDocumentListener(new DocumentListener() {
-
- public void removeUpdate(DocumentEvent e) {
- if (isInserting && isDirectEdit()) {
- endTextEditHistory();
- }
- isInserting = false;
- }
-
- public void insertUpdate(DocumentEvent e) {
- if (!isInserting && isDirectEdit()) {
- endTextEditHistory();
- }
- isInserting = true;
- }
-
- public void changedUpdate(DocumentEvent e) {
- endTextEditHistory();
- }
- });
-
- // connect the undo listener to the editor
- document.addUndoableEditListener(new UndoableEditListener() {
-
- public void undoableEditHappened(UndoableEditEvent e) {
- // if an edit is in progress, reset the timer
- if (endUndoEvent != null) {
- endUndoEvent.cancel();
- endUndoEvent = null;
- startTimerEvent();
- }
-
- // if this edit is just getting started, create a compound edit
- if (compoundEdit == null) {
- startCompoundEdit();
- startTimerEvent();
- }
-
- compoundEdit.addEdit(e.getEdit());
- undoAction.updateUndoState();
- redoAction.updateRedoState();
- }
- });
- }
-
- // update the document object that's in use
- textarea.setDocument(document,
- code.getSelectionStart(), code.getSelectionStop(),
- code.getScrollPosition());
-
-// textarea.requestFocus(); // get the caret blinking
- textarea.requestFocusInWindow(); // required for caret blinking
-
- this.undo = code.getUndo();
- undoAction.updateUndoState();
- redoAction.updateRedoState();
- }
-
- /**
- * @return true if the text is being edited from direct input from typing and
- * not shortcuts that manipulate text
- */
- boolean isDirectEdit() {
- return endUndoEvent != null;
- }
-
- void startTimerEvent() {
- endUndoEvent = new TimerTask() {
- public void run() {
- endTextEditHistory();
- }
- };
- timer.schedule(endUndoEvent, 3000);
- // let the gc eat the cancelled events
- timer.purge();
- }
-
- void endTextEditHistory() {
- if (endUndoEvent != null) {
- endUndoEvent.cancel();
- endUndoEvent = null;
- }
- stopCompoundEdit();
- }
-
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
-
-
- /**
- * Implements Edit → Cut.
- */
- public void handleCut() {
- textarea.cut();
- sketch.setModified(true);
- }
-
-
- /**
- * Implements Edit → Copy.
- */
- public void handleCopy() {
- textarea.copy();
- }
-
-
- public void handleCopyAsHTML() {
- textarea.copyAsHTML();
- statusNotice("Code formatted as HTML has been copied to the clipboard.");
- }
-
-
- /**
- * Implements Edit → Paste.
- */
- public void handlePaste() {
- textarea.paste();
- sketch.setModified(true);
- }
-
-
- /**
- * Implements Edit → Select All.
- */
- public void handleSelectAll() {
- textarea.selectAll();
- }
-
-// /**
-// * @param moveUp
-// * true to swap the selected lines with the line above, false to swap
-// * with the line beneath
-// */
- /*
- public void handleMoveLines(boolean moveUp) {
- startCompoundEdit();
-
- int startLine = textarea.getSelectionStartLine();
- int stopLine = textarea.getSelectionStopLine();
-
- // if more than one line is selected and none of the characters of the end
- // line are selected, don't move that line
- if (startLine != stopLine
- && textarea.getSelectionStop() == textarea.getLineStartOffset(stopLine))
- stopLine--;
-
- int replacedLine = moveUp ? startLine - 1 : stopLine + 1;
- if (replacedLine < 0 || replacedLine >= textarea.getLineCount())
- return;
-
- final String source = getText();
-
- int replaceStart = textarea.getLineStartOffset(replacedLine);
- int replaceEnd = textarea.getLineStopOffset(replacedLine);
- if (replaceEnd == source.length() + 1)
- replaceEnd--;
-
- int selectionStart = textarea.getLineStartOffset(startLine);
- int selectionEnd = textarea.getLineStopOffset(stopLine);
- if (selectionEnd == source.length() + 1)
- selectionEnd--;
-
- String replacedText = source.substring(replaceStart, replaceEnd);
- String selectedText = source.substring(selectionStart, selectionEnd);
- if (replacedLine == textarea.getLineCount() - 1) {
- replacedText += "\n";
- selectedText = selectedText.substring(0, selectedText.length() - 1);
- } else if (stopLine == textarea.getLineCount() - 1) {
- selectedText += "\n";
- replacedText = replacedText.substring(0, replacedText.length() - 1);
- }
-
- int newSelectionStart, newSelectionEnd;
- if (moveUp) {
- // Change the selection, then change the line above
- textarea.select(selectionStart, selectionEnd);
- textarea.setSelectedText(replacedText);
-
- textarea.select(replaceStart, replaceEnd);
- textarea.setSelectedText(selectedText);
-
- newSelectionStart = textarea.getLineStartOffset(startLine - 1);
- newSelectionEnd = textarea.getLineStopOffset(stopLine - 1) - 1;
- } else {
- // Change the line beneath, then change the selection
- textarea.select(replaceStart, replaceEnd);
- textarea.setSelectedText(selectedText);
-
- textarea.select(selectionStart, selectionEnd);
- textarea.setSelectedText(replacedText);
-
- newSelectionStart = textarea.getLineStartOffset(startLine + 1);
- newSelectionEnd = textarea.getLineStopOffset(stopLine + 1) - 1;
- }
-
- textarea.select(newSelectionStart, newSelectionEnd);
- stopCompoundEdit();
- }
- */
-
-
- /*
- public void handleDeleteLines() {
- int startLine = textarea.getSelectionStartLine();
- int stopLine = textarea.getSelectionStopLine();
-
- int start = textarea.getLineStartOffset(startLine);
- int end = textarea.getLineStopOffset(stopLine);
- if (end == getText().length() + 1)
- end--;
-
- textarea.select(start, end);
- textarea.setSelectedText("");
- }
- */
-
-
- public void handleAutoFormat() {
- final String source = getText();
-
- try {
- final String formattedText = createFormatter().format(source);
- // save current (rough) selection point
- int selectionEnd = getSelectionStop();
-
-// boolean wasVisible =
-// textarea.getSelectionStopLine() >= textarea.getFirstLine() &&
-// textarea.getSelectionStopLine() < textarea.getLastLine();
-
- // make sure the caret would be past the end of the text
- if (formattedText.length() < selectionEnd - 1) {
- selectionEnd = formattedText.length() - 1;
- }
-
- if (formattedText.equals(source)) {
- statusNotice(Language.text("editor.status.autoformat.no_changes"));
- } else {
- // replace with new bootiful text
- // selectionEnd hopefully at least in the neighborhood
- int scrollPos = textarea.getVerticalScrollPosition();
- setText(formattedText);
- setSelection(selectionEnd, selectionEnd);
-
- // Put the scrollbar position back, otherwise it jumps on each format.
- // Since we're not doing a good job of maintaining position anyway,
- // a more complicated workaround here is fairly pointless.
- // http://code.google.com/p/processing/issues/detail?id=1533
- if (scrollPos != textarea.getVerticalScrollPosition()) {
-// boolean wouldBeVisible =
-// scrollPos >= textarea.getFirstLine() &&
-// scrollPos < textarea.getLastLine();
-//
-// // if it was visible, and now it's not, then allow the scroll
-// if (!(wasVisible && !wouldBeVisible)) {
- textarea.setVerticalScrollPosition(scrollPos);
-// }
- }
- getSketch().setModified(true);
- // mark as finished
- statusNotice(Language.text("editor.status.autoformat.finished"));
- }
-
- } catch (final Exception e) {
- statusError(e);
- }
- }
-
-
- abstract public String getCommentPrefix();
-
-
- protected void handleCommentUncomment() {
- startCompoundEdit();
-
- String prefix = getCommentPrefix();
- int prefixLen = prefix.length();
-
- int startLine = textarea.getSelectionStartLine();
- int stopLine = textarea.getSelectionStopLine();
-
- int lastLineStart = textarea.getLineStartOffset(stopLine);
- int selectionStop = textarea.getSelectionStop();
- // If the selection ends at the beginning of the last line,
- // then don't (un)comment that line.
- if (selectionStop == lastLineStart) {
- // Though if there's no selection, don't do that
- if (textarea.isSelectionActive()) {
- stopLine--;
- }
- }
-
- // If the text is empty, ignore the user.
- // Also ensure that all lines are commented (not just the first)
- // when determining whether to comment or uncomment.
- int length = textarea.getDocumentLength();
- boolean commented = true;
- for (int i = startLine; commented && (i <= stopLine); i++) {
- int pos = textarea.getLineStartOffset(i);
- if (pos + prefixLen > length) {
- commented = false;
- } else {
- // Check the first characters to see if it's already a comment.
- String begin = textarea.getText(pos, prefixLen);
- //System.out.println("begin is '" + begin + "'");
- commented = begin.equals(prefix);
- }
- }
-
- for (int line = startLine; line <= stopLine; line++) {
- int location = textarea.getLineStartOffset(line);
- if (commented) {
- // remove a comment
- textarea.select(location, location + prefixLen);
- if (textarea.getSelectedText().equals(prefix)) {
- textarea.setSelectedText("");
- }
- } else {
- // add a comment
- textarea.select(location, location);
- textarea.setSelectedText(prefix);
- }
- }
- // Subtract one from the end, otherwise selects past the current line.
- // (Which causes subsequent calls to keep expanding the selection)
- textarea.select(textarea.getLineStartOffset(startLine),
- textarea.getLineStopOffset(stopLine) - 1);
- stopCompoundEdit();
- sketch.setModified(true);
- }
-
-
- public void handleIndent() {
- handleIndentOutdent(true);
- }
-
-
- public void handleOutdent() {
- handleIndentOutdent(false);
- }
-
-
- public void handleIndentOutdent(boolean indent) {
- int tabSize = Preferences.getInteger("editor.tabs.size");
- String tabString = Editor.EMPTY.substring(0, tabSize);
-
- startCompoundEdit();
-
- int startLine = textarea.getSelectionStartLine();
- int stopLine = textarea.getSelectionStopLine();
-
- // If the selection ends at the beginning of the last line,
- // then don't (un)comment that line.
- int lastLineStart = textarea.getLineStartOffset(stopLine);
- int selectionStop = textarea.getSelectionStop();
- if (selectionStop == lastLineStart) {
- // Though if there's no selection, don't do that
- if (textarea.isSelectionActive()) {
- stopLine--;
- }
- }
-
- for (int line = startLine; line <= stopLine; line++) {
- int location = textarea.getLineStartOffset(line);
-
- if (indent) {
- textarea.select(location, location);
- textarea.setSelectedText(tabString);
-
- } else { // outdent
- int last = Math.min(location + tabSize, textarea.getDocumentLength());
- textarea.select(location, last);
- // Don't eat code if it's not indented
- if (textarea.getSelectedText().equals(tabString)) {
- textarea.setSelectedText("");
- }
- }
- }
- // Subtract one from the end, otherwise selects past the current line.
- // (Which causes subsequent calls to keep expanding the selection)
- textarea.select(textarea.getLineStartOffset(startLine),
- textarea.getLineStopOffset(stopLine) - 1);
- stopCompoundEdit();
- sketch.setModified(true);
- }
-
-
- static public boolean checkParen(char[] array, int index, int stop) {
-// boolean paren = false;
-// int stepper = i + 1;
-// while (stepper < mlength) {
-// if (array[stepper] == '(') {
-// paren = true;
-// break;
-// }
-// stepper++;
-// }
- while (index < stop) {
-// if (array[index] == '(') {
-// return true;
-// } else if (!Character.isWhitespace(array[index])) {
-// return false;
-// }
- switch (array[index]) {
- case '(':
- return true;
-
- case ' ':
- case '\t':
- case '\n':
- case '\r':
- index++;
- break;
-
- default:
-// System.out.println("defaulting because " + array[index] + " " + PApplet.hex(array[index]));
- return false;
- }
- }
-// System.out.println("exiting " + new String(array, index, stop - index));
- return false;
- }
-
-
- protected boolean functionable(char c) {
- return (c == '_') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
- }
-
-
- /**
- * Check the current selection for reference. If no selection is active,
- * expand the current selection.
- * @return
- */
- protected String referenceCheck(boolean selectIfFound) {
- int start = textarea.getSelectionStart();
- int stop = textarea.getSelectionStop();
- if (stop < start) {
- int temp = stop;
- stop = start;
- start = temp;
- }
- char[] c = textarea.getText().toCharArray();
-
-// System.out.println("checking reference");
- if (start == stop) {
- while (start > 0 && functionable(c[start - 1])) {
- start--;
- }
- while (stop < c.length && functionable(c[stop])) {
- stop++;
- }
-// System.out.println("start is stop");
- }
- String text = new String(c, start, stop - start).trim();
-// System.out.println(" reference piece is '" + text + "'");
- if (checkParen(c, stop, c.length)) {
- text += "_";
- }
- String ref = mode.lookupReference(text);
- if (selectIfFound) {
- textarea.select(start, stop);
- }
- return ref;
- }
-
-
- protected void handleFindReference() {
- String ref = referenceCheck(true);
- if (ref != null) {
- showReference(ref + ".html");
- } else {
- String text = textarea.getSelectedText().trim();
- if (text.length() == 0) {
- statusNotice(Language.text("editor.status.find_reference.select_word_first"));
- } else {
- statusNotice(Language.interpolate("editor.status.find_reference.not_available", text));
- }
- }
- }
-
-
- /*
- protected void handleFindReference() {
- String text = textarea.getSelectedText().trim();
-
- if (text.length() == 0) {
- statusNotice("First select a word to find in the reference.");
-
- } else {
- char[] c = textarea.getText().toCharArray();
- int after = Math.max(textarea.getSelectionStart(), textarea.getSelectionStop());
- if (checkParen(c, after, c.length)) {
- text += "_";
- System.out.println("looking up ref for " + text);
- }
- String referenceFile = mode.lookupReference(text);
- System.out.println("reference file is " + referenceFile);
- if (referenceFile == null) {
- statusNotice("No reference available for \"" + text + "\"");
- } else {
- showReference(referenceFile + ".html");
- }
- }
- }
-
-
- protected void handleFindReference() {
- String text = textarea.getSelectedText().trim();
-
- if (text.length() == 0) {
- statusNotice("First select a word to find in the reference.");
-
- } else {
- String referenceFile = mode.lookupReference(text);
- //System.out.println("reference file is " + referenceFile);
- if (referenceFile == null) {
- statusNotice("No reference available for \"" + text + "\"");
- } else {
- showReference(referenceFile + ".html");
- }
- }
- }
- */
-
-
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
-
-
- /**
- * Set the location of the sketch run window. Used by Runner to update the
- * Editor about window drag events while the sketch is running.
- */
- public void setSketchLocation(Point p) {
- sketchWindowLocation = p;
- }
-
-
- /**
- * Get the last location of the sketch's run window. Used by Runner to make
- * the window show up in the same location as when it was last closed.
- */
- public Point getSketchLocation() {
- return sketchWindowLocation;
- }
-
-
-// public void internalCloseRunner() {
-// mode.internalCloseRunner(this);
-// }
-
-
- /**
- * Check if the sketch is modified and ask user to save changes.
- * @return false if canceling the close/quit operation
- */
- protected boolean checkModified() {
- if (!sketch.isModified()) return true;
-
- // As of Processing 1.0.10, this always happens immediately.
- // http://dev.processing.org/bugs/show_bug.cgi?id=1456
-
- // With Java 7u40 on OS X, need to bring the window forward.
- toFront();
-
- String prompt = "Save changes to " + sketch.getName() + "? ";
-
- if (!Base.isMacOS()) {
- int result =
- JOptionPane.showConfirmDialog(this, prompt, "Close",
- JOptionPane.YES_NO_CANCEL_OPTION,
- JOptionPane.QUESTION_MESSAGE);
-
- if (result == JOptionPane.YES_OPTION) {
- return handleSave(true);
-
- } else if (result == JOptionPane.NO_OPTION) {
- return true; // ok to continue
-
- } else if (result == JOptionPane.CANCEL_OPTION ||
- result == JOptionPane.CLOSED_OPTION) {
- return false;
-
- } else {
- throw new IllegalStateException();
- }
-
- } else {
- // This code is disabled unless Java 1.5 is being used on Mac OS X
- // because of a Java bug that prevents the initial value of the
- // dialog from being set properly (at least on my MacBook Pro).
- // The bug causes the "Don't Save" option to be the highlighted,
- // blinking, default. This sucks. But I'll tell you what doesn't
- // suck--workarounds for the Mac and Apple's snobby attitude about it!
- // I think it's nifty that they treat their developers like dirt.
-
- // Pane formatting adapted from the quaqua guide
- // http://www.randelshofer.ch/quaqua/guide/joptionpane.html
- JOptionPane pane =
- new JOptionPane(" " +
- " " +
- "" + Language.text("save.title") + "" +
- "
" + Language.text("save.hint") + "
",
- JOptionPane.QUESTION_MESSAGE);
-
- String[] options = new String[] {
- Language.text("save.btn.save"), Language.text("prompt.cancel"), Language.text("save.btn.dont_save")
- };
- pane.setOptions(options);
-
- // highlight the safest option ala apple hig
- pane.setInitialValue(options[0]);
-
- // on macosx, setting the destructive property places this option
- // away from the others at the lefthand side
- pane.putClientProperty("Quaqua.OptionPane.destructiveOption",
- new Integer(2));
-
- JDialog dialog = pane.createDialog(this, null);
- dialog.setVisible(true);
-
- Object result = pane.getValue();
- if (result == options[0]) { // save (and close/quit)
- return handleSave(true);
-
- } else if (result == options[2]) { // don't save (still close/quit)
- return true;
-
- } else { // cancel?
- return false;
- }
- }
- }
-
-
- /**
- * Open a sketch from a particular path, but don't check to save changes.
- * Used by Sketch.saveAs() to re-open a sketch after the "Save As"
- */
-// protected void handleOpenUnchecked(String path, int codeIndex,
-// int selStart, int selStop, int scrollPos) {
-// internalCloseRunner();
-// handleOpenInternal(path);
-// // Replacing a document that may be untitled. If this is an actual
-// // untitled document, then editor.untitled will be set by Base.
-// untitled = false;
-//
-// sketch.setCurrentCode(codeIndex);
-// textarea.select(selStart, selStop);
-// textarea.setScrollPosition(scrollPos);
-// }
-
-
- /**
- * Second stage of open, occurs after having checked to see if the
- * modifications (if any) to the previous sketch need to be saved.
- */
- protected boolean handleOpenInternal(String path) {
- // check to make sure that this .pde file is
- // in a folder of the same name
- final File file = new File(path);
- final File parentFile = new File(file.getParent());
- final String parentName = parentFile.getName();
- final String defaultName = parentName + "." + mode.getDefaultExtension();
- final File altFile = new File(file.getParent(), defaultName);
-
- if (defaultName.equals(file.getName())) {
- // no beef with this guy
- } else if (altFile.exists()) {
- // The user selected a source file from the same sketch,
- // but open the file with the default extension instead.
- path = altFile.getAbsolutePath();
- } else if (!mode.canEdit(file)) {
- final String modeName = (mode.getTitle().equals("Java")) ? "Processing"
- : mode.getTitle();
- Base
- .showWarning("Bad file selected", modeName
- + " can only open its own sketches\nand other files ending in "
- + mode.getDefaultExtension(), null);
- return false;
- } else {
- final String properParent =
- file.getName().substring(0, file.getName().lastIndexOf('.'));
-
- Object[] options = { Language.text("prompt.ok"), Language.text("prompt.cancel") };
- String prompt =
- "The file \"" + file.getName() + "\" needs to be inside\n" +
- "a sketch folder named \"" + properParent + "\".\n" +
- "Create this folder, move the file, and continue?";
-
- int result = JOptionPane.showOptionDialog(this,
- prompt,
- "Moving",
- JOptionPane.YES_NO_OPTION,
- JOptionPane.QUESTION_MESSAGE,
- null,
- options,
- options[0]);
-
- if (result == JOptionPane.YES_OPTION) {
- // create properly named folder
- File properFolder = new File(file.getParent(), properParent);
- if (properFolder.exists()) {
- Base.showWarning("Error",
- "A folder named \"" + properParent + "\" " +
- "already exists. Can't open sketch.", null);
- return false;
- }
- if (!properFolder.mkdirs()) {
- //throw new IOException("Couldn't create sketch folder");
- Base.showWarning("Error",
- "Could not create the sketch folder.", null);
- return false;
- }
- // copy the sketch inside
- File properPdeFile = new File(properFolder, file.getName());
- File origPdeFile = new File(path);
- try {
- Base.copyFile(origPdeFile, properPdeFile);
- } catch (IOException e) {
- Base.showWarning("Error", "Could not copy to a proper location.", e);
- return false;
- }
-
- // remove the original file, so user doesn't get confused
- origPdeFile.delete();
-
- // update with the new path
- path = properPdeFile.getAbsolutePath();
-
- } else if (result == JOptionPane.NO_OPTION) {
- return false;
- }
- }
-
- try {
- sketch = new Sketch(path, this);
- } catch (IOException e) {
- Base.showWarning("Error", "Could not create the sketch.", e);
- return false;
- }
- // Disabling for 3.0a4
- if (false && Preferences.getBoolean("editor.watcher")) {
- initFileChangeListener();
- }
-
- header.rebuild();
- updateTitle();
- // Disable untitled setting from previous document, if any
-// untitled = false;
-
- // Store information on who's open and running
- // (in case there's a crash or something that can't be recovered)
- // TODO this probably need not be here because of the Recent menu, right?
- Preferences.save();
-
- // opening was successful
- return true;
-
-// } catch (Exception e) {
-// e.printStackTrace();
-// statusError(e);
-// return false;
-// }
- }
-
- //used to prevent the fileChangeListener from asking for reloads after internal changes
- public void setWatcherSave() {
- watcherSave = true;
- }
-
- //set to true when the sketch is saved from inside processing
- private boolean watcherSave;
-
- //the key which is being used to poll the fs for changes
- private WatchKey watcherKey = null;
-
- private void initFileChangeListener() {
- try {
- WatchService watchService = FileSystems.getDefault().newWatchService();
- Path sp = sketch.getFolder().toPath();
- watcherKey = sp.register(watchService,
- StandardWatchEventKinds.ENTRY_CREATE,
- StandardWatchEventKinds.ENTRY_DELETE,
- StandardWatchEventKinds.ENTRY_MODIFY);
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- final WatchKey finKey = watcherKey;
-
- //if the key is null for some reason, don't bother attaching a listener to it
- if (finKey != null) {
- // the key can now be polled for changes in the files
- addWindowFocusListener(new WindowFocusListener() {
- @Override
- public void windowGainedFocus(WindowEvent arg0) {
- //we switched locations (saveAs), ignore old things
- if (watcherKey != finKey) {
- return;
- }
- // check preference here for enabled or not?
-
- //if the directory was deleted, then don't scan
- if (finKey.isValid()) {
- List> events = finKey.pollEvents();
- if (!watcherSave) {
- processFileEvents(events);
- }
- }
-
- List> events = finKey.pollEvents();
- if (!watcherSave)
- processFileEvents(events);
- }
-
- @Override
- public void windowLostFocus(WindowEvent arg0) {
- //we switched locations (saveAs), ignore old things
- if (watcherKey != finKey) {
- return;
- }
- List> events = finKey.pollEvents();
- //don't ask to reload a file we saved
- if (!watcherSave) {
- processFileEvents(events);
- }
- watcherSave = false;
- }
- });
- }
- }
-
-
- /**
- * Called when a file is changed.
- * @param events the list of events that have occured in the sketch folder
- */
- private void processFileEvents(List> events) {
- for (WatchEvent> e : events) {
- boolean sketchFile = false;
- Path file = ((Path) e.context()).getFileName();
- System.out.println(file);
- for (String s : getMode().getExtensions()) {
- // if it is a change to a file with a known extension
- if (file.toString().endsWith(s)) {
- sketchFile = true;
- break;
- }
- }
- //if the file is not a known type, then go the the next event
- if (!sketchFile) {
- continue;
- }
-
- int response =
- Base.showYesNoQuestion(Editor.this,
- "File Modified",
- "Your sketch has been modified externally",
- "Would you like to reload the sketch?");
- if (response == 0) {
- //grab the 'main' code in case this reload tries to delete everything
- File sc = sketch.getMainFile();
- //reload the sketch
- try {
- sketch.reload();
- header.rebuild();
- } catch (Exception f) {
- if (sketch.getCodeCount() < 1) {
- Base.showWarning("Canceling Reload",
- "You cannot delete the last code file in a sketch.");
- //if they deleted the last file, re-save the SketchCode
- try {
- //make a blank file
- sc.createNewFile();
- } catch (IOException e1) {
- //if that didn't work, tell them it's un-recoverable
- Base.showError("Reload failed", "The sketch contains no code files", e1);
- //don't try to reload again after the double fail
- //this editor is probably trashed by this point, but a save-as might be possible
- break;
- }
- //don't ask for another reload after this save
- watcherSave = true;
- return;
- }
- }
- //now that we've reloaded once, don't try to reload again
- break;
- }
- }
- watcherSave = false;
- }
-
- /**
- * Set the title of the PDE window based on the current sketch, i.e.
- * something like "sketch_070752a - Processing 0126"
- */
- public void updateTitle() {
- setTitle(sketch.getName() + " | Processing " + Base.getVersionName());
-
- if (!sketch.isUntitled()) {
- // set current file for OS X so that cmd-click in title bar works
- File sketchFile = sketch.getMainFile();
- getRootPane().putClientProperty("Window.documentFile", sketchFile);
- } else {
- // per other applications, don't set this until the file has been saved
- getRootPane().putClientProperty("Window.documentFile", null);
- }
- }
-
-
- /**
- * Actually handle the save command. If 'immediately' is set to false,
- * this will happen in another thread so that the message area
- * will update and the save button will stay highlighted while the
- * save is happening. If 'immediately' is true, then it will happen
- * immediately. This is used during a quit, because invokeLater()
- * won't run properly while a quit is happening. This fixes
- * Bug 276.
- */
- public boolean handleSave(boolean immediately) {
-// handleStop(); // 0136
-
- setWatcherSave();
- if (sketch.isUntitled()) {
- return handleSaveAs();
- // need to get the name, user might also cancel here
-
- } else if (immediately) {
- handleSaveImpl();
-
- } else {
- EventQueue.invokeLater(new Runnable() {
- public void run() {
- handleSaveImpl();
- }
- });
- }
- return true;
- }
-
-
- protected void handleSaveImpl() {
- statusNotice(Language.text("editor.status.saving"));
- try {
- if (sketch.save()) {
- statusNotice(Language.text("editor.status.saving.done"));
- } else {
- statusEmpty();
- }
-
- } catch (Exception e) {
- // show the error as a message in the window
- statusError(e);
-
- // zero out the current action,
- // so that checkModified2 will just do nothing
- //checkModifiedMode = 0;
- // this is used when another operation calls a save
- }
- }
-
-
- public boolean handleSaveAs() {
- statusNotice(Language.text("editor.status.saving"));
- try {
- if (sketch.saveAs()) {
- // Disabling for 3.0a4
- if (false && Preferences.getBoolean("editor.watcher")) {
- // "Save As" moves where the files are, so a listener must be
- // attached to the new location.
- // TODO shouldn't this remove the old listener?
- initFileChangeListener();
- }
- // statusNotice("Done Saving.");
- // status is now printed from Sketch so that "Done Saving."
- // is only printed after Save As when progress bar is shown.
- } else {
- statusNotice(Language.text("editor.status.saving.canceled"));
- return false;
- }
- } catch (Exception e) {
- // show the error as a message in the window
- statusError(e);
- }
- return true;
- }
-
-
- /**
- * Handler for File → Page Setup.
- */
- public void handlePageSetup() {
- //printerJob = null;
- if (printerJob == null) {
- printerJob = PrinterJob.getPrinterJob();
- }
- if (pageFormat == null) {
- pageFormat = printerJob.defaultPage();
- }
- pageFormat = printerJob.pageDialog(pageFormat);
- //System.out.println("page format is " + pageFormat);
- }
-
-
- /**
- * Handler for File → Print.
- */
- public void handlePrint() {
- statusNotice(Language.text("editor.status.printing"));
- //printerJob = null;
- if (printerJob == null) {
- printerJob = PrinterJob.getPrinterJob();
- }
- if (pageFormat != null) {
- //System.out.println("setting page format " + pageFormat);
- printerJob.setPrintable(textarea.getPrintable(), pageFormat);
- } else {
- printerJob.setPrintable(textarea.getPrintable());
- }
- // set the name of the job to the code name
- printerJob.setJobName(sketch.getCurrentCode().getPrettyName());
-
- if (printerJob.printDialog()) {
- try {
- printerJob.print();
- statusNotice(Language.text("editor.status.printing.done"));
-
- } catch (PrinterException pe) {
- statusError(Language.text("editor.status.printing.error"));
- pe.printStackTrace();
- }
- } else {
- statusNotice(Language.text("editor.status.printing.canceled"));
- }
- //printerJob = null; // clear this out?
- }
-
-
- /**
- * Grab current contents of the sketch window, advance the console,
- * stop any other running sketches... not in that order.
- */
- public void prepareRun() {
- internalCloseRunner();
- statusEmpty();
-
- // do this to advance/clear the terminal window / dos prompt / etc
- for (int i = 0; i < 10; i++) System.out.println();
-
- // clear the console on each run, unless the user doesn't want to
- if (Preferences.getBoolean("console.auto_clear")) {
- console.clear();
- }
-
- // make sure the user didn't hide the sketch folder
- sketch.ensureExistence();
-
- // make sure any edits have been stored
- //current.setProgram(editor.getText());
- sketch.getCurrentCode().setProgram(getText());
-
-// // if an external editor is being used, need to grab the
-// // latest version of the code from the file.
-// if (Preferences.getBoolean("editor.external")) {
-// sketch.reload();
-// }
- }
-
-
- /**
- * Halt the current runner for whatever reason. Might be the VM dying,
- * the window closing, an error...
- */
- abstract public void internalCloseRunner();
-
-
- abstract public void deactivateRun();
-
-
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
-
-
- /**
- * Show an error in the status bar.
- */
- public void statusError(String what) {
- status.error(what);
- //new Exception("deactivating RUN").printStackTrace();
-// toolbar.deactivate(EditorToolbar.RUN);
- }
-
-
- /**
- * Show an exception in the editor status bar.
- */
- public void statusError(Exception e) {
- e.printStackTrace();
-// if (e == null) {
-// System.err.println("Editor.statusError() was passed a null exception.");
-// return;
-// }
-
- if (e instanceof SketchException) {
- SketchException re = (SketchException) e;
- if (re.hasCodeIndex()) {
- sketch.setCurrentCode(re.getCodeIndex());
- }
- if (re.hasCodeLine()) {
- int line = re.getCodeLine();
- // subtract one from the end so that the \n ain't included
- if (line >= textarea.getLineCount()) {
- // The error is at the end of this current chunk of code,
- // so the last line needs to be selected.
- line = textarea.getLineCount() - 1;
- if (textarea.getLineText(line).length() == 0) {
- // The last line may be zero length, meaning nothing to select.
- // If so, back up one more line.
- line--;
- }
- }
- if (line < 0 || line >= textarea.getLineCount()) {
- System.err.println("Bad error line: " + line);
- } else {
- textarea.select(textarea.getLineStartOffset(line),
- textarea.getLineStopOffset(line) - 1);
- }
- }
- }
-
- // Since this will catch all Exception types, spend some time figuring
- // out which kind and try to give a better error message to the user.
- String mess = e.getMessage();
- if (mess != null) {
- String javaLang = "java.lang.";
- if (mess.indexOf(javaLang) == 0) {
- mess = mess.substring(javaLang.length());
- }
- String rxString = "RuntimeException: ";
- if (mess.startsWith(rxString)) {
- mess = mess.substring(rxString.length());
- }
- statusError(mess);
- }
-// e.printStackTrace();
- }
-
-
- /**
- * Show a notice message in the editor status bar.
- */
- public void statusNotice(String msg) {
- status.notice(msg);
- }
-
-
- public void clearNotice(String msg) {
- if (status.message.equals(msg)) {
- statusEmpty();
- }
- }
-
-
- /**
- * Returns the current notice message in the editor status bar.
- */
- public String getStatusMessage(){
- return status.message;
- }
-
-
- /**
- * Returns the current mode of the editor status bar: NOTICE, ERR or EDIT.
- */
- public int getStatusMode(){
- return status.mode;
- }
-
-
- /**
- * Clear the status area.
- */
- public void statusEmpty() {
- statusNotice(EMPTY);
- }
-
-
- public void startIndeterminate() {
- status.startIndeterminate();
- }
-
-
- public void stopIndeterminate() {
- status.stopIndeterminate();
- }
-
-
- public void statusHalt() {
- // stop called by someone else
- }
-
-
- public boolean isHalted() {
- return false;
- }
-
-
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
-
-
- /**
- * Returns the edit popup menu.
- */
- class TextAreaPopup extends JPopupMenu {
- JMenuItem cutItem;
- JMenuItem copyItem;
- JMenuItem discourseItem;
- JMenuItem referenceItem;
-
-
- public TextAreaPopup() {
- JMenuItem item;
-
- cutItem = new JMenuItem(Language.text("menu.edit.cut"));
- cutItem.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- handleCut();
- }
- });
- this.add(cutItem);
-
- copyItem = new JMenuItem(Language.text("menu.edit.copy"));
- copyItem.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- handleCopy();
- }
- });
- this.add(copyItem);
-
- discourseItem = new JMenuItem(Language.text("menu.edit.copy_as_html"));
- discourseItem.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- handleCopyAsHTML();
- }
- });
- this.add(discourseItem);
-
- item = new JMenuItem(Language.text("menu.edit.paste"));
- item.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- handlePaste();
- }
- });
- this.add(item);
-
- item = new JMenuItem(Language.text("menu.edit.select_all"));
- item.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- handleSelectAll();
- }
- });
- this.add(item);
-
- this.addSeparator();
-
- item = new JMenuItem(Language.text("menu.edit.comment_uncomment"));
- item.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- handleCommentUncomment();
- }
- });
- this.add(item);
-
- item = new JMenuItem("\u2192 "+Language.text("menu.edit.increase_indent"));
- item.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- handleIndentOutdent(true);
- }
- });
- this.add(item);
-
- item = new JMenuItem("\u2190 "+Language.text("menu.edit.decrease_indent"));
- item.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- handleIndentOutdent(false);
- }
- });
- this.add(item);
-
- this.addSeparator();
-
- referenceItem = new JMenuItem(Language.text("find_in_reference"));
- referenceItem.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- handleFindReference();
- }
- });
- this.add(referenceItem);
- }
-
- // if no text is selected, disable copy and cut menu items
- public void show(Component component, int x, int y) {
-// if (textarea.isSelectionActive()) {
-// cutItem.setEnabled(true);
-// copyItem.setEnabled(true);
-// discourseItem.setEnabled(true);
-//
-//// String sel = textarea.getSelectedText().trim();
-//// String referenceFile = mode.lookupReference(sel);
-//// referenceItem.setEnabled(referenceFile != null);
-//
-// } else {
-// cutItem.setEnabled(false);
-// copyItem.setEnabled(false);
-// discourseItem.setEnabled(false);
-//// referenceItem.setEnabled(false);
-// }
- boolean active = textarea.isSelectionActive();
- cutItem.setEnabled(active);
- copyItem.setEnabled(active);
- discourseItem.setEnabled(active);
-
- referenceItem.setEnabled(referenceCheck(false) != null);
- super.show(component, x, y);
- }
- }
-}
diff --git a/app/src/processing/app/EditorConsole.java b/app/src/processing/app/EditorConsole.java
deleted file mode 100644
index 9355398413..0000000000
--- a/app/src/processing/app/EditorConsole.java
+++ /dev/null
@@ -1,449 +0,0 @@
-/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
-
-/*
- Part of the Processing project - http://processing.org
-
- Copyright (c) 2004-10 Ben Fry and Casey Reas
- Copyright (c) 2001-04 Massachusetts Institute of Technology
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software Foundation,
- Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-package processing.app;
-
-import java.awt.*;
-import java.awt.event.*;
-import java.io.*;
-
-import javax.swing.*;
-import javax.swing.text.*;
-import processing.core.PApplet;
-
-import java.text.SimpleDateFormat;
-import java.util.*;
-
-
-/**
- * Message console that sits below the editing area.
- *
- * Be careful when debugging this class, because if it's throwing exceptions,
- * don't take over System.err, and debug while watching just System.out
- * or just call println() or whatever directly to systemOut or systemErr.
- *
- * Also note that encodings will not work properly when run from Eclipse. This
- * means that if you use non-ASCII characters in a println() or some such,
- * the characters won't print properly in the Processing and/or Eclipse console.
- * It seems that Eclipse's console-grabbing and that of Processing don't
- * get along with one another. Use 'ant run' to work on encoding-related issues.
- */
-public class EditorConsole extends JScrollPane {
- Editor editor;
-
- JTextPane consoleTextPane;
- BufferedStyledDocument consoleDoc;
-
- MutableAttributeSet stdStyle;
- MutableAttributeSet errStyle;
-
- int maxLineCount;
-
- // Single static instance shared because there's only one real System.out.
- // Within the input handlers, the currentConsole variable will be used to
- // echo things to the correct location.
-
- static PrintStream systemOut;
- static PrintStream systemErr;
-
- static PrintStream consoleOut;
- static PrintStream consoleErr;
-
- static OutputStream stdoutFile;
- static OutputStream stderrFile;
-
- static EditorConsole currentConsole;
-
- // For 0185, moved the first init to this static { } block, so that we never
- // have a situation that causes systemOut/Err to not be set properly.
- static {
- systemOut = System.out;
- systemErr = System.err;
-
- // placing everything inside a try block because this can be a dangerous
- // time for the lights to blink out and crash for and obscure reason.
- try {
- // Create output files that will have a randomized name. Has to
- // be randomized otherwise another instance of Processing (or one of its
- // sister IDEs) might collide with the file causing permissions problems.
- // The files and folders are not deleted on exit because they may be
- // needed for debugging or bug reporting.
- SimpleDateFormat formatter = new SimpleDateFormat("yyMMdd");
- String randy = PApplet.nf((int) (1000 * Math.random()), 4);
- String stamp = formatter.format(new Date()) + "_" + randy;
-
- File consoleDir = Base.getSettingsFile("console");
- consoleDir.mkdirs();
- File outFile = new File(consoleDir, stamp + ".out");
- stdoutFile = new FileOutputStream(outFile);
- File errFile = new File(consoleDir, stamp + ".err");
- stderrFile = new FileOutputStream(errFile);
-
- consoleOut = new PrintStream(new EditorConsoleStream(false));
- consoleErr = new PrintStream(new EditorConsoleStream(true));
-
- System.setOut(consoleOut);
- System.setErr(consoleErr);
-
-// } catch (Exception e) {
-// stdoutFile = null;
-// stderrFile = null;
-//
-// e.printStackTrace();
-// Base.showWarning("Console Error",
-// "A problem occurred while trying to open the\n" +
-// "files used to store the console output.", e);
- } catch (Exception e) {
- stdoutFile = null;
- stderrFile = null;
-
- consoleOut = null;
- consoleErr = null;
-
- System.setOut(systemOut);
- System.setErr(systemErr);
-
- e.printStackTrace(systemErr);
- }
- }
-
-
- public EditorConsole(Editor editor) {
- this.editor = editor;
-
- maxLineCount = Preferences.getInteger("console.length");
-
- consoleDoc = new BufferedStyledDocument(10000, maxLineCount);
- consoleTextPane = new JTextPane(consoleDoc);
- consoleTextPane.setEditable(false);
-
- updateMode();
-
- // add the jtextpane to this scrollpane
- this.setViewportView(consoleTextPane);
-
- // to fix ugliness.. normally macosx java 1.3 puts an
- // ugly white border around this object, so turn it off.
- if (Base.isMacOS()) {
- setBorder(null);
- }
-
- // periodically post buffered messages to the console
- // should the interval come from the preferences file?
- new javax.swing.Timer(250, new ActionListener() {
- public void actionPerformed(ActionEvent evt) {
- // only if new text has been added
- if (consoleDoc.hasAppendage) {
- // insert the text that's been added in the meantime
- consoleDoc.insertAll();
- // always move to the end of the text as it's added
- consoleTextPane.setCaretPosition(consoleDoc.getLength());
- }
- }
- }).start();
- }
-
-
- /**
- * Update the font family and sizes based on the Preferences window.
- */
- protected void updateAppearance() {
- String fontFamily = Preferences.get("editor.font.family");
- int fontSize = Preferences.getInteger("console.font.size");
- StyleConstants.setFontFamily(stdStyle, fontFamily);
- StyleConstants.setFontSize(stdStyle, fontSize);
- StyleConstants.setFontFamily(errStyle, fontFamily);
- StyleConstants.setFontSize(errStyle, fontSize);
- clear(); // otherwise we'll have mixed fonts
- }
-
-
- /**
- * Change coloring, fonts, etc in response to a mode change.
- */
- protected void updateMode() {
- Mode mode = editor.getMode();
-
- // necessary?
- MutableAttributeSet standard = new SimpleAttributeSet();
- StyleConstants.setAlignment(standard, StyleConstants.ALIGN_LEFT);
- consoleDoc.setParagraphAttributes(0, 0, standard, true);
-
- Font font = Preferences.getFont("console.font");
-
- // build styles for different types of console output
- Color bgColor = mode.getColor("console.color");
- Color fgColorOut = mode.getColor("console.output.color");
- Color fgColorErr = mode.getColor("console.error.color");
-
- stdStyle = new SimpleAttributeSet();
- StyleConstants.setForeground(stdStyle, fgColorOut);
- StyleConstants.setBackground(stdStyle, bgColor);
- StyleConstants.setFontSize(stdStyle, font.getSize());
- StyleConstants.setFontFamily(stdStyle, font.getFamily());
- StyleConstants.setBold(stdStyle, font.isBold());
- StyleConstants.setItalic(stdStyle, font.isItalic());
-
- errStyle = new SimpleAttributeSet();
- StyleConstants.setForeground(errStyle, fgColorErr);
- StyleConstants.setBackground(errStyle, bgColor);
- StyleConstants.setFontSize(errStyle, font.getSize());
- StyleConstants.setFontFamily(errStyle, font.getFamily());
- StyleConstants.setBold(errStyle, font.isBold());
- StyleConstants.setItalic(errStyle, font.isItalic());
-
- if (UIManager.getLookAndFeel().getID().equals("Nimbus")) {
- getViewport().setBackground(bgColor);
- consoleTextPane.setOpaque(false);
- consoleTextPane.setBackground(new Color(0, 0, 0, 0));
- } else {
- consoleTextPane.setBackground(bgColor);
- }
-
- // calculate height of a line of text in pixels
- // and size window accordingly
- FontMetrics metrics = this.getFontMetrics(font);
- int height = metrics.getAscent() + metrics.getDescent();
- int lines = Preferences.getInteger("console.lines"); //, 4);
- int sizeFudge = 6; //10; // unclear why this is necessary, but it is
- setPreferredSize(new Dimension(1024, (height * lines) + sizeFudge));
- setMinimumSize(new Dimension(1024, (height * 4) + sizeFudge));
- }
-
-
- static public void setEditor(Editor editor) {
- currentConsole = editor.console;
- }
-
-
- /**
- * Close the streams so that the temporary files can be deleted.
- *
- * File.deleteOnExit() cannot be used because the stdout and stderr
- * files are inside a folder, and have to be deleted before the
- * folder itself is deleted, which can't be guaranteed when using
- * the deleteOnExit() method.
- */
- public void handleQuit() {
- // replace original streams to remove references to console's streams
- System.setOut(systemOut);
- System.setErr(systemErr);
-
- try {
- // close the PrintStream
- if (consoleOut != null) consoleOut.close();
- if (consoleErr != null) consoleErr.close();
-
- // also have to close the original FileOutputStream
- // otherwise it won't be shut down completely
- if (stdoutFile != null) stdoutFile.close();
- if (stderrFile != null) stderrFile.close();
-
- } catch (IOException e) {
- e.printStackTrace(systemErr);
- }
- }
-
-
- synchronized public void message(String what, boolean err) {
- if (err) {
- systemErr.print(what);
- } else {
- systemOut.print(what);
- }
-
- if (err && (what.contains("invalid context 0x0") || (what.contains("invalid drawable")))) {
- // Respectfully declining... This is a quirk of more recent releases of
- // Java on Mac OS X, but is widely reported as the source of any other
- // bug or problem that a user runs into. It may well be a Processing
- // bug, but until we know, we're suppressing the messages.
- } else if (err && what.contains("Make pbuffer:")) {
- // Remove initalization warning from LWJGL.
- } else if (err && what.contains("XInitThreads() called for concurrent")) {
- // "Info: XInitThreads() called for concurrent Thread support" message on Linux
- } else if (!err && what.contains("Listening for transport dt_socket at address")) {
- // Message from the JVM about the socket launch for debug
- // Listening for transport dt_socket at address: 8727
- } else {
- // Append a piece of text to the console. Swing components are NOT
- // thread-safe, and since the MessageSiphon instantiates new threads,
- // and in those callbacks, they often print output to stdout and stderr,
- // which are wrapped by EditorConsoleStream and eventually leads to
- // EditorConsole.appendText(), which directly updates the Swing text
- // components, causing deadlock. Updates are buffered to the console and
- // displayed at regular intervals on Swing's event-dispatching thread.
- // (patch by David Mellis)
- consoleDoc.appendString(what, err ? errStyle : stdStyle);
- }
- }
-
-
- public void clear() {
- try {
- consoleDoc.remove(0, consoleDoc.getLength());
- } catch (BadLocationException e) {
- // ignore the error otherwise this will cause an infinite loop
- // maybe not a good idea in the long run?
- }
- }
-
-
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
-
-
- private static class EditorConsoleStream extends OutputStream {
- //static EditorConsole current;
- final boolean err; // whether stderr or stdout
- final byte single[] = new byte[1];
-
- public EditorConsoleStream(boolean err) {
- this.err = err;
- }
-
- public void close() { }
-
- public void flush() { }
-
- public void write(byte b[]) { // appears never to be used
- write(b, 0, b.length);
- }
-
- public void write(byte b[], int offset, int length) {
- if (currentConsole != null) {
- //currentConsole.write(b, offset, length, err);
-// currentConsole.message(new String(b, offset, length), err, false);
- currentConsole.message(new String(b, offset, length), err);
- } else {
- try {
- if (err) {
- systemErr.write(b);
- } else {
- systemOut.write(b);
- }
- } catch (IOException e) { } // just ignore, where would we write?
- }
-
- final OutputStream echo = err ? stderrFile : stdoutFile;
- if (echo != null) {
- try {
- echo.write(b, offset, length);
- echo.flush();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
-
- public void write(int b) {
- single[0] = (byte) b;
- write(single, 0, 1);
- }
- }
-}
-
-
-// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
-
-
-/**
- * Buffer updates to the console and output them in batches. For info, see:
- * http://java.sun.com/products/jfc/tsc/articles/text/element_buffer and
- * http://javatechniques.com/public/java/docs/gui/jtextpane-speed-part2.html
- * appendString() is called from multiple threads, and insertAll from the
- * swing event thread, so they need to be synchronized
- */
-class BufferedStyledDocument extends DefaultStyledDocument {
- ArrayList elements = new ArrayList();
- int maxLineLength, maxLineCount;
- int currentLineLength = 0;
- boolean needLineBreak = false;
- boolean hasAppendage = false;
-
- public BufferedStyledDocument(int maxLineLength, int maxLineCount) {
- this.maxLineLength = maxLineLength;
- this.maxLineCount = maxLineCount;
- }
-
- /** buffer a string for insertion at the end of the DefaultStyledDocument */
- public synchronized void appendString(String str, AttributeSet a) {
- // do this so that it's only updated when needed (otherwise console
- // updates every 250 ms when an app isn't even running.. see bug 180)
- hasAppendage = true;
-
- // process each line of the string
- while (str.length() > 0) {
- // newlines within an element have (almost) no effect, so we need to
- // replace them with proper paragraph breaks (start and end tags)
- if (needLineBreak || currentLineLength > maxLineLength) {
- elements.add(new ElementSpec(a, ElementSpec.EndTagType));
- elements.add(new ElementSpec(a, ElementSpec.StartTagType));
- currentLineLength = 0;
- }
-
- if (str.indexOf('\n') == -1) {
- elements.add(new ElementSpec(a, ElementSpec.ContentType,
- str.toCharArray(), 0, str.length()));
- currentLineLength += str.length();
- needLineBreak = false;
- str = str.substring(str.length()); // eat the string
- } else {
- elements.add(new ElementSpec(a, ElementSpec.ContentType,
- str.toCharArray(), 0, str.indexOf('\n') + 1));
- needLineBreak = true;
- str = str.substring(str.indexOf('\n') + 1); // eat the line
- }
- }
- }
-
- /** insert the buffered strings */
- public synchronized void insertAll() {
- ElementSpec[] elementArray = new ElementSpec[elements.size()];
- elements.toArray(elementArray);
-
- try {
- // check how many lines have been used so far
- // if too many, shave off a few lines from the beginning
- Element element = super.getDefaultRootElement();
- int lineCount = element.getElementCount();
- int overage = lineCount - maxLineCount;
- if (overage > 0) {
- // if 1200 lines, and 1000 lines is max,
- // find the position of the end of the 200th line
- //systemOut.println("overage is " + overage);
- Element lineElement = element.getElement(overage);
- if (lineElement == null) return; // do nuthin
-
- int endOffset = lineElement.getEndOffset();
- // remove to the end of the 200th line
- super.remove(0, endOffset);
- }
- super.insert(super.getLength(), elementArray);
-
- } catch (BadLocationException e) {
- // ignore the error otherwise this will cause an infinite loop
- // maybe not a good idea in the long run?
- }
- elements.clear();
- hasAppendage = false;
- }
-}
diff --git a/app/src/processing/app/EditorHeader.java b/app/src/processing/app/EditorHeader.java
deleted file mode 100644
index b49be2cd5b..0000000000
--- a/app/src/processing/app/EditorHeader.java
+++ /dev/null
@@ -1,662 +0,0 @@
-/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
-
-/*
- Part of the Processing project - http://processing.org
-
- Copyright (c) 2004-13 Ben Fry and Casey Reas
- Copyright (c) 2001-04 Massachusetts Institute of Technology
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software Foundation,
- Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-package processing.app;
-
-import java.awt.*;
-import java.awt.event.*;
-import java.awt.geom.GeneralPath;
-import java.util.Arrays;
-
-import javax.swing.*;
-
-
-/**
- * Sketch tabs at the top of the editor window.
- */
-public class EditorHeader extends JComponent {
- // standard UI sizing (OS-specific, but generally consistent)
- static final int SCROLLBAR_WIDTH = 16;
- // amount of space on the left edge before the tabs start
- static final int MARGIN_WIDTH = 6;
- // distance from the righthand side of a tab to the drop-down arrow
- static final int ARROW_GAP_WIDTH = 8;
- // indent x/y for notch on the tab
- static final int NOTCH = 0;
- // how far to raise the tab from the bottom of this Component
- static final int TAB_HEIGHT = 25;
- // line that continues across all of the tabs for the current one
- static final int TAB_STRETCH = 3;
- // amount of extra space between individual tabs
- static final int TAB_BETWEEN = 2;
- // amount of margin on the left/right for the text on the tab
- static final int TEXT_MARGIN = 10;
- // width of the tab when no text visible
- // (total tab width will be this plus TEXT_MARGIN*2)
- static final int NO_TEXT_WIDTH = 10;
-
- Color bgColor;
- boolean hiding;
- Color hideColor;
-
- Color textColor[] = new Color[2];
- Color tabColor[] = new Color[2];
- Color modifiedColor;
-
- Editor editor;
-
- Tab[] tabs = new Tab[0];
- Tab[] visitOrder;
-
- Font font;
-// FontMetrics metrics;
- int fontAscent;
-
- JMenu menu;
- JPopupMenu popup;
-
- int menuLeft;
- int menuRight;
-
- //
-
- static final String STATUS[] = { "unsel", "sel" };
- static final int UNSELECTED = 0;
- static final int SELECTED = 1;
-
-// static final String WHERE[] = { "left", "mid", "right" }; //, "menu" };
-// static final int LEFT = 0;
-// static final int MIDDLE = 1;
-// static final int RIGHT = 2;
-// static final int MENU = 3;
-
- static final int PIECE_WIDTH = 4;
- static final int PIECE_HEIGHT = 33;
- Image[][] pieces;
-
- static final int ARROW_WIDTH = 14;
- static final int ARROW_HEIGHT = 14;
- static Image tabArrow;
-
- //
-
- Image offscreen;
- int sizeW, sizeH;
- int imageW, imageH;
-
- String lastNoticeName;
-
-
- public EditorHeader(Editor eddie) {
- this.editor = eddie;
-
- updateMode();
-
- addMouseListener(new MouseAdapter() {
- public void mousePressed(MouseEvent e) {
- int x = e.getX();
- int y = e.getY();
-
- if ((x > menuLeft) && (x < menuRight)) {
- popup.show(EditorHeader.this, x, y);
-
- } else {
- Sketch sketch = editor.getSketch();
-// for (int i = 0; i < sketch.getCodeCount(); i++) {
-// if ((x > tabLeft[i]) && (x < tabRight[i])) {
-// sketch.setCurrentCode(i);
-// repaint();
-// }
-// }
- for (Tab tab : tabs) {
- if (tab.contains(x)) {
- sketch.setCurrentCode(tab.index);
- repaint();
- }
- }
- }
- }
-
- public void mouseExited(MouseEvent e) {
- // only clear if it's been set
- if (lastNoticeName != null) {
- // only clear if it's the same as what we set it to
- editor.clearNotice(lastNoticeName);
- lastNoticeName = null;
- }
- }
- });
-
- addMouseMotionListener(new MouseMotionAdapter() {
- public void mouseMoved(MouseEvent e) {
- int x = e.getX();
- for (Tab tab : tabs) {
- if (tab.contains(x) && !tab.textVisible) {
- lastNoticeName = editor.getSketch().getCode(tab.index).getPrettyName();
- editor.statusNotice(lastNoticeName);
- }
- }
- }
- });
- }
-
-
-// protected String tabFile(int status, int where) {
-// return "theme/tab-" + STATUS[status] + "-" + WHERE[where];
-// }
-
-
- public void updateMode() {
- Mode mode = editor.getMode();
-// int res = Toolkit.isRetina() ? 2 : 1;
-// String suffix = "-2x.png"; // wishful thinking
-// // Some modes may not have a 2x version. If a mode doesn't have a 1x
-// // version, this will cause an error... they should always have 1x.
-// if (res == 2) {
-// if (!mode.getContentFile(tabFile(0, 0) + suffix).exists()) {
-// res = 1;
-// }
-// }
-// if (res == 1) {
-// suffix = ".png";
-// if (!mode.getContentFile(tabFile(0, 0) + suffix).exists()) {
-// suffix = ".gif";
-// }
-// }
-//
-// pieces = new Image[STATUS.length][WHERE.length];
-// for (int status = 0; status < STATUS.length; status++) {
-// for (int where = 0; where < WHERE.length; where++) {
-// //String filename = "theme/tab-" + STATUS[i] + "-" + WHERE[j] + ".gif";
-// pieces[status][where] = mode.loadImage(tabFile(status, where) + suffix);
-// }
-// }
-
- if (tabArrow == null) {
- String suffix = Toolkit.highResDisplay() ? "-2x.png" : ".png";
- tabArrow = Toolkit.getLibImage("tab-arrow" + suffix);
- }
-
- bgColor = mode.getColor("header.bgcolor");
-
- hiding = Preferences.getBoolean("buttons.hide.image");
- hideColor = mode.getColor("buttons.hide.color");
-
- textColor[SELECTED] = mode.getColor("header.text.selected.color");
- textColor[UNSELECTED] = mode.getColor("header.text.unselected.color");
- font = mode.getFont("header.text.font");
-
- tabColor[SELECTED] = mode.getColor("header.tab.selected.color");
- tabColor[UNSELECTED] = mode.getColor("header.tab.unselected.color");
-
- modifiedColor = mode.getColor("editor.selection.color");
- }
-
-
- public void paintComponent(Graphics screen) {
- if (screen == null) return;
-
- Sketch sketch = editor.getSketch();
- if (sketch == null) return; // ??
-
- Dimension size = getSize();
- if ((size.width != sizeW) || (size.height != sizeH)) {
- // component has been resized
-
- if ((size.width > imageW) || (size.height > imageH)) {
- // nix the image and recreate, it's too small
- offscreen = null;
-
- } else {
- // if the image is larger than necessary, no need to change
- sizeW = size.width;
- sizeH = size.height;
- }
- }
-
- if (offscreen == null) {
- sizeW = size.width;
- sizeH = size.height;
- imageW = sizeW;
- imageH = sizeH;
- if (Toolkit.highResDisplay()) {
- offscreen = createImage(imageW*2, imageH*2);
- } else {
- offscreen = createImage(imageW, imageH);
- }
- }
-
- Graphics g = offscreen.getGraphics();
- g.setFont(font); // need to set this each time through
-// metrics = g.getFontMetrics();
-// fontAscent = metrics.getAscent();
- if (fontAscent == 0) {
- fontAscent = (int) Toolkit.getAscent(g);
- }
-
- Graphics2D g2 = (Graphics2D) g;
-
- if (Toolkit.highResDisplay()) {
- // scale everything 2x, will be scaled down when drawn to the screen
- g2.scale(2, 2);
- if (Base.isUsableOracleJava()) {
- // Oracle Java looks better with anti-aliasing turned on
- g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
- RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
- }
- } else {
- // don't anti-alias text in retina mode w/ Apple Java
- g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
- RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
- }
-
- // set the background for the offscreen
- g.setColor(hiding ? hideColor : bgColor);
- g.fillRect(0, 0, imageW, imageH);
-
- if (!hiding) {
- editor.getMode().drawBackground(g, Preferences.GRID_SIZE);
- }
-
- if (tabs.length != sketch.getCodeCount()) {
- tabs = new Tab[sketch.getCodeCount()];
- for (int i = 0; i < tabs.length; i++) {
- tabs[i] = new Tab(i);
- }
- visitOrder = new Tab[sketch.getCodeCount() - 1];
- }
-
- int leftover =
- ARROW_GAP_WIDTH + ARROW_WIDTH + MARGIN_WIDTH; // + SCROLLBAR_WIDTH;
- int tabMax = getWidth() - leftover;
-
- // reset all tab positions
- for (Tab tab : tabs) {
- SketchCode code = sketch.getCode(tab.index);
- tab.textVisible = true;
- tab.lastVisited = code.lastVisited();
-
- // hide extensions for .pde files (or whatever else is the norm elsewhere
- boolean hide = editor.getMode().hideExtension(code.getExtension());
-// String codeName = hide ? code.getPrettyName() : code.getFileName();
- // if modified, add the li'l glyph next to the name
-// tab.text = " " + codeName + (code.isModified() ? " \u00A7" : " ");
-// tab.text = " " + codeName + " ";
- tab.text = hide ? code.getPrettyName() : code.getFileName();
-
- tab.textWidth = (int)
- font.getStringBounds(tab.text, g2.getFontRenderContext()).getWidth();
- }
-
- // make sure everything can fit
- if (!placeTabs(MARGIN_WIDTH, tabMax, null)) {
- //System.arraycopy(tabs, 0, visitOrder, 0, tabs.length);
- // always show the tab with the sketch's name
-// System.arraycopy(tabs, 1, visitOrder, 0, tabs.length - 1);
- int index = 0;
- // stock the array backwards so that the rightmost tabs are closed by default
- for (int i = tabs.length - 1; i > 0; --i) {
- visitOrder[index++] = tabs[i];
- }
- Arrays.sort(visitOrder); // sort on when visited
-// for (int i = 0; i < visitOrder.length; i++) {
-// System.out.println(visitOrder[i].index + " " + visitOrder[i].text);
-// }
-// System.out.println();
-
- // Keep shrinking the tabs one-by-one until things fit properly
- for (int i = 0; i < visitOrder.length; i++) {
- tabs[visitOrder[i].index].textVisible = false;
- if (placeTabs(MARGIN_WIDTH, tabMax, null)) {
- break;
- }
- }
- }
-
- // now actually draw the tabs
- placeTabs(MARGIN_WIDTH, tabMax, g2);
-
- // draw the dropdown menu target
- menuLeft = tabs[tabs.length - 1].right + ARROW_GAP_WIDTH;
- menuRight = menuLeft + ARROW_WIDTH;
- int arrowY = (getHeight() - TAB_HEIGHT - TAB_STRETCH) + (TAB_HEIGHT - ARROW_HEIGHT)/2;
- g.drawImage(tabArrow, menuLeft, arrowY,
- ARROW_WIDTH, ARROW_HEIGHT, null);
-// g.drawImage(pieces[popup.isVisible() ? SELECTED : UNSELECTED][MENU],
-// menuLeft, 0, null);
-
- screen.drawImage(offscreen, 0, 0, imageW, imageH, null);
- }
-
-
- private boolean placeTabs(int left, int right, Graphics2D g) {
- Sketch sketch = editor.getSketch();
- int x = left;
-
- final int bottom = getHeight() - TAB_STRETCH;
- final int top = bottom - TAB_HEIGHT;
- GeneralPath path = null;
-
- for (int i = 0; i < sketch.getCodeCount(); i++) {
- SketchCode code = sketch.getCode(i);
- Tab tab = tabs[i];
-
-// int pieceCount = 2 + (tab.textWidth / PIECE_WIDTH);
-// if (tab.textVisible == false) {
-// pieceCount = 4;
-// }
-// int pieceWidth = pieceCount * PIECE_WIDTH;
-
- int state = (code == sketch.getCurrentCode()) ? SELECTED : UNSELECTED;
- if (g != null) {
- //g.drawImage(pieces[state][LEFT], x, 0, PIECE_WIDTH, PIECE_HEIGHT, null);
- path = new GeneralPath();
- path.moveTo(x, bottom);
- path.lineTo(x, top + NOTCH);
- path.lineTo(x + NOTCH, top);
- }
- tab.left = x;
- x += TEXT_MARGIN;
-// x += PIECE_WIDTH;
-
-// int contentLeft = x;
-// for (int j = 0; j < pieceCount; j++) {
-// if (g != null) {
-// g.drawImage(pieces[state][MIDDLE], x, 0, PIECE_WIDTH, PIECE_HEIGHT, null);
-// }
-// x += PIECE_WIDTH;
-// }
-// if (g != null) {
- int drawWidth = tab.textVisible ? tab.textWidth : NO_TEXT_WIDTH;
- x += drawWidth + TEXT_MARGIN;
-// path.moveTo(x, top);
-// }
- tab.right = x;
-
- if (g != null) {
- path.lineTo(x - NOTCH, top);
- path.lineTo(x, top + NOTCH);
- path.lineTo(x, bottom);
- path.closePath();
- g.setColor(tabColor[state]);
- g.fill(path);
- // have to draw an extra outline to make things line up on retina
- g.draw(path);
- //g.drawImage(pieces[state][RIGHT], x, 0, PIECE_WIDTH, PIECE_HEIGHT, null);
-
- if (tab.textVisible) {
- int textLeft = tab.left + ((tab.right - tab.left) - tab.textWidth) / 2;
- g.setColor(textColor[state]);
-// int baseline = (int) Math.ceil((sizeH + fontAscent) / 2.0);
- //int baseline = bottom - (TAB_HEIGHT - fontAscent)/2;
- int tabHeight = TAB_HEIGHT; //bottom - top;
- int baseline = top + (tabHeight + fontAscent) / 2;
- //g.drawString(sketch.code[i].name, textLeft, baseline);
- g.drawString(tab.text, textLeft, baseline);
-// g.drawLine(tab.left, baseline-fontAscent, tab.right, baseline-fontAscent);
-// g.drawLine(tab.left, baseline, tab.right, baseline);
- }
-
- if (code.isModified()) {
- g.setColor(modifiedColor);
- g.drawLine(tab.left + NOTCH, top, tab.right - NOTCH, top);
- }
- }
-
-// if (g != null) {
-// g.drawImage(pieces[state][RIGHT], x, 0, PIECE_WIDTH, PIECE_HEIGHT, null);
-// }
-// x += PIECE_WIDTH - 1; // overlap by 1 pixel
- x += TAB_BETWEEN;
- }
-
- // Draw this last because of half-pixel overlaps on retina displays
- if (g != null) {
- g.setColor(tabColor[SELECTED]);
- g.fillRect(0, bottom, getWidth(), TAB_STRETCH);
- }
-
- return x <= right;
- }
-
-
- /**
- * Called when a new sketch is opened.
- */
- public void rebuild() {
- //System.out.println("rebuilding editor header");
- rebuildMenu();
- repaint();
- }
-
-
- public void rebuildMenu() {
- //System.out.println("rebuilding");
- if (menu != null) {
- menu.removeAll();
-
- } else {
- menu = new JMenu();
- popup = menu.getPopupMenu();
- add(popup);
- popup.setLightWeightPopupEnabled(true);
-
- /*
- popup.addPopupMenuListener(new PopupMenuListener() {
- public void popupMenuCanceled(PopupMenuEvent e) {
- // on redraw, the isVisible() will get checked.
- // actually, a repaint may be fired anyway, so this
- // may be redundant.
- repaint();
- }
-
- public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { }
- public void popupMenuWillBecomeVisible(PopupMenuEvent e) { }
- });
- */
- }
- JMenuItem item;
-
- // maybe this shouldn't have a command key anyways..
- // since we're not trying to make this a full ide..
- //item = Editor.newJMenuItem("New", 'T');
-
- /*
- item = Editor.newJMenuItem("Previous", KeyEvent.VK_PAGE_UP);
- item.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- System.out.println("prev");
- }
- });
- if (editor.sketch != null) {
- item.setEnabled(editor.sketch.codeCount > 1);
- }
- menu.add(item);
-
- item = Editor.newJMenuItem("Next", KeyEvent.VK_PAGE_DOWN);
- item.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- System.out.println("ext");
- }
- });
- if (editor.sketch != null) {
- item.setEnabled(editor.sketch.codeCount > 1);
- }
- menu.add(item);
-
- menu.addSeparator();
- */
-
- //item = new JMenuItem("New Tab");
- item = Toolkit.newJMenuItemShift(Language.text("editor.header.new_tab"), 'N');
- item.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- editor.getSketch().handleNewCode();
- editor.setWatcherSave();
- }
- });
- menu.add(item);
-
- item = new JMenuItem(Language.text("editor.header.rename"));
- item.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- editor.getSketch().handleRenameCode();
- /*
- // this is already being called by nameCode(), the second stage of rename
- if (editor.sketch.current == editor.sketch.code[0]) {
- editor.sketchbook.rebuildMenus();
- }
- */
- }
- });
- menu.add(item);
-
- item = new JMenuItem(Language.text("editor.header.delete"));
- item.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- Sketch sketch = editor.getSketch();
- if (!Base.isMacOS() && // ok on OS X
- editor.base.editors.size() == 1 && // mmm! accessor
- sketch.getCurrentCodeIndex() == 0) {
- Base.showWarning(Language.text("editor.header.delete.warning.title"),
- Language.text("editor.header.delete.warning.text"), null);
- } else {
- editor.getSketch().handleDeleteCode();
- editor.setWatcherSave();
- }
- }
- });
- menu.add(item);
-
- menu.addSeparator();
-
- // KeyEvent.VK_LEFT and VK_RIGHT will make Windows beep
-
- item = new JMenuItem(Language.text("editor.header.previous_tab"));
- KeyStroke ctrlAltLeft =
- KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, Toolkit.SHORTCUT_ALT_KEY_MASK);
- item.setAccelerator(ctrlAltLeft);
- // this didn't want to work consistently
- /*
- item.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- editor.sketch.prevCode();
- }
- });
- */
- menu.add(item);
-
- item = new JMenuItem(Language.text("editor.header.next_tab"));
- KeyStroke ctrlAltRight =
- KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, Toolkit.SHORTCUT_ALT_KEY_MASK);
- item.setAccelerator(ctrlAltRight);
- /*
- item.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- editor.sketch.nextCode();
- }
- });
- */
- menu.add(item);
-
- Sketch sketch = editor.getSketch();
- if (sketch != null) {
- menu.addSeparator();
-
- ActionListener jumpListener = new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- editor.getSketch().setCurrentCode(e.getActionCommand());
- }
- };
- for (SketchCode code : sketch.getCode()) {
- item = new JMenuItem(code.getPrettyName());
- item.addActionListener(jumpListener);
- menu.add(item);
- }
- }
- }
-
-
- public void deselectMenu() {
- repaint();
- }
-
-
- public Dimension getPreferredSize() {
- return getMinimumSize();
- }
-
-
- public Dimension getMinimumSize() {
-// if (Base.isMacOS()) {
- return new Dimension(300, Preferences.GRID_SIZE);
-// }
-// return new Dimension(300, Preferences.GRID_SIZE - 1);
- }
-
-
- public Dimension getMaximumSize() {
-// if (Base.isMacOS()) {
- return new Dimension(3000, Preferences.GRID_SIZE);
-// }
-// return new Dimension(3000, Preferences.GRID_SIZE - 1);
- }
-
-
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
-
-
- static class Tab implements Comparable {
- int index;
- int left;
- int right;
- String text;
- int textWidth;
- boolean textVisible;
- long lastVisited;
-
- Tab(int index) {
- this.index = index;
- }
-
- boolean contains(int x) {
- return x >= left && x <= right;
- }
-
- // sort by the last time visited
- public int compareTo(Object o) {
- Tab other = (Tab) o;
- // do this here to deal with situation where both are 0
- if (lastVisited == other.lastVisited) {
- return 0;
- }
- if (lastVisited == 0) {
- return -1;
- }
- if (other.lastVisited == 0) {
- return 1;
- }
- return (int) (lastVisited - other.lastVisited);
- }
- }
-}
diff --git a/app/src/processing/app/EditorLineStatus.java b/app/src/processing/app/EditorLineStatus.java
deleted file mode 100644
index ff7a1bacd8..0000000000
--- a/app/src/processing/app/EditorLineStatus.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
-
-/*
- Part of the Processing project - http://processing.org
-
- Copyright (c) 2005-07 Ben Fry and Casey Reas
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software Foundation,
- Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-package processing.app;
-
-import java.awt.*;
-
-import javax.swing.*;
-
-
-/**
- * Li'l status bar fella that shows the line number.
- */
-public class EditorLineStatus extends JComponent {
- Editor editor;
-// JEditTextArea textarea;
- int start = -1, stop;
-
- Color foreground;
- Color background;
- Font font;
- int high;
-
- String text = "";
-
-
- public EditorLineStatus(Editor editor) {
- this.editor = editor;
-
-// textarea = editor.getTextArea();
- // not pretty, but it just does one thing...
-// textarea.editorLineStatus = this;
- editor.getTextArea().editorLineStatus = this;
-
- updateMode();
- }
-
-
- public void updateMode() {
- Mode mode = editor.getMode();
- background = mode.getColor("linestatus.bgcolor");
- font = mode.getFont("linestatus.font");
- foreground = mode.getColor("linestatus.color");
- high = mode.getInteger("linestatus.height");
- }
-
-
- public void set(int newStart, int newStop) {
- if ((newStart == start) && (newStop == stop)) return;
-
- start = newStart;
- stop = newStop;
-
- /*
- if (start == stop) {
- text = "Line " + (start + 1);
- } else {
- text = "Lines " + (start + 1) + " to " + (stop + 1);
- }
- */
- if (start == stop) {
- text = String.valueOf(start+1);
- } else {
- text = (start+1) + " - " + (stop+1);
- }
-
- repaint();
- }
-
-
- public void paintComponent(Graphics g) {
- Graphics2D g2 = (Graphics2D) g;
- g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
- RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
-
- g.setColor(background);
- Dimension size = getSize();
- g.fillRect(0, 0, size.width, size.height);
-
- g.setFont(font);
- g.setColor(foreground);
- int baseline = (high + g.getFontMetrics().getAscent()) / 2;
- // With 7u40 (or Source Code Sans?) things seem to be edged up a bit
- g.drawString(text, 6, baseline - 1);
- }
-
-
- public Dimension getPreferredSize() {
- return new Dimension(300, high);
- }
-
- public Dimension getMinimumSize() {
- return getPreferredSize();
- }
-
- public Dimension getMaximumSize() {
- return new Dimension(3000, high);
- }
-}
diff --git a/app/src/processing/app/EditorStatus.java b/app/src/processing/app/EditorStatus.java
deleted file mode 100644
index 0f7fc5b42e..0000000000
--- a/app/src/processing/app/EditorStatus.java
+++ /dev/null
@@ -1,433 +0,0 @@
-/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
-
-/*
- Part of the Processing project - http://processing.org
-
- Copyright (c) 2004-10 Ben Fry and Casey Reas
- Copyright (c) 2001-04 Massachusetts Institute of Technology
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software Foundation,
- Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-package processing.app;
-
-import java.awt.*;
-//import java.awt.event.*;
-
-import javax.swing.*;
-
-
-/**
- * Panel just below the editing area that contains status messages.
- */
-public class EditorStatus extends JPanel {
- Color[] bgcolor;
- Color[] fgcolor;
-
- @Deprecated
- static final int BUTTON_HEIGHT = 24;
-
- static public final int NOTICE = 0;
- static public final int ERR = 1;
- static public final int EDIT = 2;
-
- static final int YES = 1;
- static final int NO = 2;
- static final int CANCEL = 3;
- static final int OK = 4;
-
- static final String NO_MESSAGE = "";
-
- Editor editor;
-
- int mode;
- String message;
-
- Font font;
- FontMetrics metrics;
- int ascent;
-
- Image offscreen;
- int sizeW, sizeH;
-
-// JButton cancelButton;
-// JButton okButton;
-// JTextField editField;
-
- int response;
-
- boolean indeterminate;
- Thread thread;
-
-
-
- public EditorStatus(Editor editor) {
- this.editor = editor;
- empty();
- updateMode();
- }
-
-
- public void updateMode() {
- Mode mode = editor.getMode();
- bgcolor = new Color[] {
- mode.getColor("status.notice.bgcolor"),
- mode.getColor("status.error.bgcolor"),
- mode.getColor("status.edit.bgcolor")
- };
-
- fgcolor = new Color[] {
- mode.getColor("status.notice.fgcolor"),
- mode.getColor("status.error.fgcolor"),
- mode.getColor("status.edit.fgcolor")
- };
-
- font = mode.getFont("status.font");
- metrics = null;
- }
-
-
- public void empty() {
- mode = NOTICE;
- message = NO_MESSAGE;
- repaint();
- }
-
-
- public void notice(String message) {
- mode = NOTICE;
- this.message = message;
- repaint();
- }
-
-
- public void unnotice(String unmessage) {
- if (message.equals(unmessage)) empty();
- }
-
-
- public void error(String message) {
- mode = ERR;
- this.message = message;
- repaint();
- }
-
-
-// public void edit(String message, String dflt) {
-// mode = EDIT;
-// this.message = message;
-//
-// response = 0;
-// okButton.setVisible(true);
-// cancelButton.setVisible(true);
-// editField.setVisible(true);
-// editField.setText(dflt);
-// editField.selectAll();
-// editField.requestFocusInWindow();
-//
-// repaint();
-// }
-
-
-// public void unedit() {
-// okButton.setVisible(false);
-// cancelButton.setVisible(false);
-// editField.setVisible(false);
-// editor.textarea.requestFocusInWindow();
-// empty();
-// }
-
-
- public void startIndeterminate() {
- indeterminate = true;
- thread = new Thread() {
- public void run() {
- while (Thread.currentThread() == thread) {
- repaint();
- try {
- Thread.sleep(1000 / 10);
- } catch (InterruptedException e) { }
- }
- }
- };
- thread.setName("Editor Status");
- thread.start();
- }
-
-
- public void stopIndeterminate() {
- indeterminate = false;
- thread = null;
- repaint();
- }
-
-
- public void paintComponent(Graphics screen) {
-// if (okButton == null) setup();
-
- Dimension size = getSize();
- if ((size.width != sizeW) || (size.height != sizeH)) {
- // component has been resized
- offscreen = null;
- }
-
- if (offscreen == null) {
- sizeW = size.width;
- sizeH = size.height;
-// setButtonBounds();
- if (Toolkit.highResDisplay()) {
- offscreen = createImage(sizeW*2, sizeH*2);
- } else {
- offscreen = createImage(sizeW, sizeH);
- }
- }
-
- Graphics g = offscreen.getGraphics();
-
- Graphics2D g2 = (Graphics2D) g;
- if (Toolkit.highResDisplay()) {
- g2.scale(2, 2);
- if (Base.isUsableOracleJava()) {
- // Oracle Java looks better with anti-aliasing turned on
- g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
- RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
- }
- } else {
- g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
- RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
- }
-
- g.setFont(font);
- if (metrics == null) {
- metrics = g.getFontMetrics();
- ascent = metrics.getAscent();
- }
-
- g.setColor(bgcolor[mode]);
- g.fillRect(0, 0, sizeW, sizeH);
-
- g.setColor(fgcolor[mode]);
- g.setFont(font); // needs to be set each time on osx
- g.drawString(message, Preferences.GUI_SMALL, (sizeH + ascent) / 2);
-
- if (indeterminate) {
- //int x = cancelButton.getX();
- //int w = cancelButton.getWidth();
- int w = Preferences.BUTTON_WIDTH;
- int x = getWidth() - Preferences.GUI_SMALL - w;
- int y = getHeight() / 3;
- int h = getHeight() / 3;
- g.setColor(new Color(0x80000000, true));
- g.drawRect(x, y, w, h);
- for (int i = 0; i < 10; i++) {
- int r = (int) (x + Math.random() * w);
- g.drawLine(r, y, r, y+h);
- }
- }
-
- screen.drawImage(offscreen, 0, 0, sizeW, sizeH, null);
- }
-
-
- /*
- protected void setup() {
- if (okButton == null) {
- cancelButton = new JButton(Preferences.PROMPT_CANCEL);
- okButton = new JButton(Preferences.PROMPT_OK);
-
- cancelButton.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- if (mode == EDIT) {
- unedit();
- //editor.toolbar.clear();
- }
- }
- });
-
- okButton.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- // answering to rename/new code question
- if (mode == EDIT) { // this if() isn't (shouldn't be?) necessary
- String answer = editField.getText();
- editor.getSketch().nameCode(answer);
- unedit();
- }
- }
- });
-
- // !@#(* aqua ui #($*(( that turtle-neck wearing #(** (#$@)(
- // os9 seems to work if bg of component is set, but x still a bastard
- if (Base.isMacOS()) {
- //yesButton.setBackground(bgcolor[EDIT]);
- //noButton.setBackground(bgcolor[EDIT]);
- cancelButton.setBackground(bgcolor[EDIT]);
- okButton.setBackground(bgcolor[EDIT]);
- }
- setLayout(null);
-
- add(cancelButton);
- add(okButton);
-
- cancelButton.setVisible(false);
- okButton.setVisible(false);
-
- editField = new JTextField();
- // disabling, was not in use
- //editField.addActionListener(this);
-
- //if (Base.platform != Base.MACOSX) {
- editField.addKeyListener(new KeyAdapter() {
-
- // Grab ESC with keyPressed, because it's not making it to keyTyped
- public void keyPressed(KeyEvent event) {
- if (event.getKeyChar() == KeyEvent.VK_ESCAPE) {
- unedit();
- //editor.toolbar.clear();
- event.consume();
- }
- }
-
- // use keyTyped to catch when the feller is actually
- // added to the text field. with keyTyped, as opposed to
- // keyPressed, the keyCode will be zero, even if it's
- // enter or backspace or whatever, so the keychar should
- // be used instead. grr.
- public void keyTyped(KeyEvent event) {
- //System.out.println("got event " + event);
- int c = event.getKeyChar();
-
- if (c == KeyEvent.VK_ENTER) { // accept the input
- String answer = editField.getText();
- editor.getSketch().nameCode(answer);
- unedit();
- event.consume();
-
- // easier to test the affirmative case than the negative
- } else if ((c == KeyEvent.VK_BACK_SPACE) ||
- (c == KeyEvent.VK_DELETE) ||
- (c == KeyEvent.VK_RIGHT) ||
- (c == KeyEvent.VK_LEFT) ||
- (c == KeyEvent.VK_UP) ||
- (c == KeyEvent.VK_DOWN) ||
- (c == KeyEvent.VK_HOME) ||
- (c == KeyEvent.VK_END) ||
- (c == KeyEvent.VK_SHIFT)) {
- // these events are ignored
-
-// } else if (c == KeyEvent.VK_ESCAPE) {
-// unedit();
-// editor.toolbar.clear();
-// event.consume();
-
- } else if (c == KeyEvent.VK_SPACE) {
- String t = editField.getText();
- int start = editField.getSelectionStart();
- int end = editField.getSelectionEnd();
- editField.setText(t.substring(0, start) + "_" +
- t.substring(end));
- editField.setCaretPosition(start+1);
- event.consume();
-
- } else if ((c == '_') || (c == '.') || // allow .pde and .java
- ((c >= 'A') && (c <= 'Z')) ||
- ((c >= 'a') && (c <= 'z'))) {
- // these are ok, allow them through
-
- } else if ((c >= '0') && (c <= '9')) {
- // getCaretPosition == 0 means that it's the first char
- // and the field is empty.
- // getSelectionStart means that it *will be* the first
- // char, because the selection is about to be replaced
- // with whatever is typed.
- if ((editField.getCaretPosition() == 0) ||
- (editField.getSelectionStart() == 0)) {
- // number not allowed as first digit
- //System.out.println("bad number bad");
- event.consume();
- }
- } else {
- event.consume();
- //System.out.println("code is " + code + " char = " + c);
- }
- //System.out.println("code is " + code + " char = " + c);
- }
- });
- add(editField);
- editField.setVisible(false);
- }
- }
-
-
- private void setButtonBounds() {
- int top = (sizeH - BUTTON_HEIGHT) / 2;
- int eachButton = Preferences.GUI_SMALL + Preferences.BUTTON_WIDTH;
-
- int cancelLeft = sizeW - eachButton;
- int noLeft = cancelLeft - eachButton;
- int yesLeft = noLeft - eachButton;
-
- //yesButton.setLocation(yesLeft, top);
- //noButton.setLocation(noLeft, top);
- cancelButton.setLocation(cancelLeft, top);
- okButton.setLocation(noLeft, top);
-
- //yesButton.setSize(Preferences.BUTTON_WIDTH, Preferences.BUTTON_HEIGHT);
- //noButton.setSize(Preferences.BUTTON_WIDTH, Preferences.BUTTON_HEIGHT);
- cancelButton.setSize(Preferences.BUTTON_WIDTH, BUTTON_HEIGHT);
- okButton.setSize(Preferences.BUTTON_WIDTH, BUTTON_HEIGHT);
-
- // edit field height is awkward, and very different between mac and pc,
- // so use at least the preferred height for now.
- int editWidth = 2*Preferences.BUTTON_WIDTH;
- int editHeight = editField.getPreferredSize().height;
- int editTop = (1 + sizeH - editHeight) / 2; // add 1 for ceil
- editField.setBounds(yesLeft - Preferences.BUTTON_WIDTH, editTop,
- editWidth, editHeight);
- }
- */
-
-
- public Dimension getPreferredSize() {
- return getMinimumSize();
- }
-
-
- public Dimension getMinimumSize() {
- return new Dimension(300, Preferences.GRID_SIZE);
- }
-
-
- public Dimension getMaximumSize() {
- return new Dimension(3000, Preferences.GRID_SIZE);
- }
-
-
- /*
- public void actionPerformed(ActionEvent e) {
- if (e.getSource() == cancelButton) {
- if (mode == EDIT) unedit();
- //editor.toolbar.clear();
-
- } else if (e.getSource() == okButton) {
- // answering to rename/new code question
- if (mode == EDIT) { // this if() isn't (shouldn't be?) necessary
- String answer = editField.getText();
- editor.getSketch().nameCode(answer);
- unedit();
- }
- }
- }
- */
-}
diff --git a/app/src/processing/app/EditorToolbar.java b/app/src/processing/app/EditorToolbar.java
deleted file mode 100644
index 8e19de1023..0000000000
--- a/app/src/processing/app/EditorToolbar.java
+++ /dev/null
@@ -1,599 +0,0 @@
-/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
-
-/*
- Part of the Processing project - http://processing.org
-
- Copyright (c) 2004-13 Ben Fry and Casey Reas
- Copyright (c) 2001-04 Massachusetts Institute of Technology
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, version 2.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software Foundation,
- Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-package processing.app;
-
-import java.awt.*;
-import java.awt.event.*;
-import java.awt.image.BufferedImage;
-import java.util.ArrayList;
-
-import javax.swing.*;
-import javax.swing.event.*;
-
-
-/**
- * run/stop/etc buttons for the ide
- */
-public abstract class EditorToolbar extends JComponent implements MouseInputListener, KeyListener {
-
- /** Width of each toolbar button. */
- static final int BUTTON_WIDTH = 27;
- /** Height of each toolbar button. */
-// static final int BUTTON_HEIGHT = 32;
- /** The amount of space between groups of buttons on the toolbar. */
- static final int BUTTON_GAP = 5;
- /** Size (both width and height) of the buttons in the source image. */
- static final int BUTTON_IMAGE_SIZE = 33;
-
- static final int INACTIVE = 0;
- static final int ROLLOVER = 1;
- static final int ACTIVE = 2;
-
- protected Base base;
- protected Editor editor;
- protected Mode mode;
-
- Image offscreen;
- int width, height;
-
- Color bgColor;
- boolean hiding;
- Color hideColor;
-
- protected Button rollover;
-
- Font statusFont;
- int statusAscent;
- Color statusColor;
-
- boolean shiftPressed;
-
- // what the mode indicator looks like
- Color modeButtonColor;
- Font modeTextFont;
- int modeTextAscent;
- Color modeTextColor;
- String modeTitle;
- int modeX1, modeY1;
- int modeX2, modeY2;
- JMenu modeMenu;
-
- protected ArrayList