diff --git a/README.md b/README.md
index c01b621bd..0746ca999 100644
--- a/README.md
+++ b/README.md
@@ -4,6 +4,8 @@ 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.
+
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),
@@ -15,18 +17,18 @@ changes made by [processing-bugs](https://github.com/processing-bugs), it may be
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!
-The [processing-web](https://github.com/processing/processing-web/) repository
-contains reference, examples, and the site.
+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.)
The instructions for building the source [are here](https://github.com/processing/processing/wiki/Build-Instructions).
Someday we'll also write code style guidelines, fix all these bugs,
-throw together hundreds of unit tests, and solve the Israeli-Palestinian conflict.
+throw together hundreds of unit tests,
+and get rich off all this stuff that we're giving away for free.
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).
Ben Fry, 3 February 2013
-Last updated 21 April 2013
+Last updated 30 July 2014
diff --git a/app/.classpath b/app/.classpath
index 25495070c..e12f72e7e 100644
--- a/app/.classpath
+++ b/app/.classpath
@@ -6,8 +6,7 @@
-
-
+
diff --git a/app/.settings/org.eclipse.jdt.core.prefs b/app/.settings/org.eclipse.jdt.core.prefs
deleted file mode 100644
index 60fcdf705..000000000
--- a/app/.settings/org.eclipse.jdt.core.prefs
+++ /dev/null
@@ -1,381 +0,0 @@
-eclipse.preferences.version=1
-org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=disabled
-org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore
-org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull
-org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault
-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.7
-org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
-org.eclipse.jdt.core.compiler.compliance=1.7
-org.eclipse.jdt.core.compiler.debug.lineNumber=generate
-org.eclipse.jdt.core.compiler.debug.localVariable=generate
-org.eclipse.jdt.core.compiler.debug.sourceFile=generate
-org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
-org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
-org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
-org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
-org.eclipse.jdt.core.compiler.problem.deadCode=ignore
-org.eclipse.jdt.core.compiler.problem.deprecation=warning
-org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
-org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
-org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
-org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
-org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
-org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
-org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
-org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled
-org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
-org.eclipse.jdt.core.compiler.problem.finalParameterBound=ignore
-org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
-org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
-org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
-org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled
-org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
-org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore
-org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=warning
-org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
-org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
-org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore
-org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
-org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled
-org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore
-org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
-org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
-org.eclipse.jdt.core.compiler.problem.missingSerialVersion=ignore
-org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore
-org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
-org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
-org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
-org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning
-org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error
-org.eclipse.jdt.core.compiler.problem.nullReference=ignore
-org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error
-org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning
-org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
-org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
-org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore
-org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore
-org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore
-org.eclipse.jdt.core.compiler.problem.rawTypeReference=ignore
-org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning
-org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
-org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore
-org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
-org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
-org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
-org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
-org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
-org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
-org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
-org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=disabled
-org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
-org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
-org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled
-org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=ignore
-org.eclipse.jdt.core.compiler.problem.unclosedCloseable=ignore
-org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
-org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
-org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
-org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning
-org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
-org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore
-org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
-org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
-org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
-org.eclipse.jdt.core.compiler.problem.unusedImport=warning
-org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
-org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
-org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore
-org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
-org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
-org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
-org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
-org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
-org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
-org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
-org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
-org.eclipse.jdt.core.compiler.source=1.7
-org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
-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
-org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=18
-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_compact_if=16
-org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
-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_method_declaration=0
-org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
-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_resources_in_try=80
-org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=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_union_type_in_multicatch=16
-org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
-org.eclipse.jdt.core.formatter.blank_lines_after_package=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
-org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
-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_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
-org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
-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_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.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.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_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.insert_new_line_before_root_tags=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.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.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
-org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
-org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
-org.eclipse.jdt.core.formatter.indent_empty_lines=false
-org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
-org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
-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_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
-org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
-org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
-org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
-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_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
-org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
-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_and_in_type_parameter=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_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
-org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
-org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
-org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
-org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
-org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
-org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
-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_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_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
-org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
-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_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_unary_operator=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=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_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
-org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
-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_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_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
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
-org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
-org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
-org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
-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_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_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
-org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
-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_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_imple_if_on_one_line=false
-org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
-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.number_of_blank_lines_at_beginning_of_method_body=0
-org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
-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.use_on_off_tags=false
-org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
-org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
-org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
-org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java
index 6b4f86bce..f8fc94126 100644
--- a/app/src/processing/app/Base.java
+++ b/app/src/processing/app/Base.java
@@ -46,9 +46,9 @@ import processing.mode.java.JavaMode;
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 = 228;
+ static private final int REVISION = 229;
/** This might be replaced by main() if there's a lib/version.txt file. */
- static private String VERSION_NAME = "0228"; //$NON-NLS-1$
+ static private String VERSION_NAME = "0229"; //$NON-NLS-1$
/** Set true if this a proper release rather than a numbered revision. */
// static private boolean RELEASE = false;
@@ -300,12 +300,12 @@ public class Base {
// try {
// Class.forName("processing.mode.java2.DebugMode");
ModeContribution experimentalContrib =
- ModeContribution.load(this, getContentFile("modes/experimental"), //$NON-NLS-1$
+ ModeContribution.load(this, getContentFile("modes/ExperimentalMode"), //$NON-NLS-1$
"processing.mode.experimental.ExperimentalMode"); //$NON-NLS-1$
if (experimentalContrib != null) {
Mode experimentalMode = experimentalContrib.getMode();
//coreModes = new Mode[] { javaMode, androidMode, experimentalMode };
- coreModes = new Mode[] { javaMode, experimentalMode };
+ coreModes = new Mode[] { experimentalMode, javaMode };
}
// } catch (ClassNotFoundException e) { }
@@ -604,38 +604,37 @@ public class Base {
}
+ /**
+ * The call has already checked to make sure this sketch is not modified,
+ * now change the mode.
+ */
protected void changeMode(Mode mode) {
if (activeEditor.getMode() != mode) {
Sketch sketch = activeEditor.getSketch();
- if (sketch.isModified()) {
- Base.showWarning("Save",
- "Please save the sketch before changing the mode.",
- null);
- return;
- }
nextMode = mode;
-
- // 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) {
- final File props = new File(sketch.getCodeFolder(), "sketch.properties");
- saveModeSettings(props, nextMode);
+
+ 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);
- handleOpen(sketch.getMainFilePath());
- } else {
- // If you're changing modes, and there's nothing in the current sketch, you probably
- // don't intend to keep the old, wrong-mode editor around.
- if (sketch.isUntitled()) {
- 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;
+ }
+ }
+ if (newModeCanHandleCurrentSource) {
+ final File props = new File(sketch.getCodeFolder(), "sketch.properties");
+ saveModeSettings(props, nextMode);
+ handleClose(activeEditor, true);
+ handleOpen(sketch.getMainFilePath());
+ }
}
}
}
@@ -930,14 +929,18 @@ public class Base {
return null;
}
- // System.err.println(" editors: " + editors);
// Cycle through open windows to make sure that it's not already open.
for (Editor editor : editors) {
- if (editor.getSketch().getMainFile().equals(file)) {
- editor.toFront();
- // move back to the top of the recent list
- handleRecent(editor);
- return editor;
+ // 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;
+ }
}
}
@@ -960,8 +963,6 @@ public class Base {
// Editor.State state = new Editor.State(editors);
Editor editor = nextMode.createEditor(this, path, state);
if (editor == null) {
- // if it's the last editor window
-// if (editors.size() == 0 && defaultFileMenu == 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.
if (nextMode == coreModes[0]) {
@@ -974,15 +975,14 @@ public class Base {
editor = coreModes[0].createEditor(this, path, state);
}
}
-
+
// Make sure that the sketch actually loaded
- if (editor.getSketch() == null) {
-// System.err.println("sketch was null, getting out of handleOpen");
+ Sketch sketch = editor.getSketch();
+ if (sketch == null) {
return null; // Just walk away quietly
}
-// editor.untitled = untitled;
- editor.getSketch().setUntitled(untitled);
+ sketch.setUntitled(untitled);
editors.add(editor);
handleRecent(editor);
@@ -1867,41 +1867,15 @@ public class Base {
}
-// static public String getExamplesPath() {
-// return examplesFolder.getAbsolutePath();
-// }
-
-// public File getExamplesFolder() {
-// return examplesFolder;
-// }
-
-
-// static public String getLibrariesPath() {
-// return librariesFolder.getAbsolutePath();
-// }
-
-
-// public File getLibrariesFolder() {
-// return librariesFolder;
-// }
-
-
-// static public File getToolsFolder() {
static public File getToolsFolder() {
-// return toolsFolder;
return getContentFile("tools");
}
-// static public String getToolsPath() {
-// return toolsFolder.getAbsolutePath();
-// }
-
-
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.get("sketchbook.path"); //$NON-NLS-1$
+ String sketchbookPath = Preferences.getSketchbookPath();
if (sketchbookPath != null) {
sketchbookFolder = new File(sketchbookPath);
if (!sketchbookFolder.exists()) {
@@ -1918,7 +1892,7 @@ public class Base {
// If no path is set, get the default sketchbook folder for this platform
if (sketchbookFolder == null) {
sketchbookFolder = getDefaultSketchbookFolder();
- Preferences.set("sketchbook.path", sketchbookFolder.getAbsolutePath());
+ Preferences.setSketchbookPath(sketchbookFolder.getAbsolutePath());
if (!sketchbookFolder.exists()) {
sketchbookFolder.mkdirs();
}
@@ -1933,19 +1907,17 @@ public class Base {
public void setSketchbookFolder(File folder) {
sketchbookFolder = folder;
- Preferences.set("sketchbook.path", folder.getAbsolutePath());
+ Preferences.setSketchbookPath(folder.getAbsolutePath());
rebuildSketchbookMenus();
}
static public File getSketchbookFolder() {
-// return new File(Preferences.get("sketchbook.path"));
return sketchbookFolder;
}
static public File getSketchbookLibrariesFolder() {
-// return new File(getSketchbookFolder(), "libraries");
return new File(sketchbookFolder, "libraries");
}
diff --git a/app/src/processing/app/ColorChooser.java b/app/src/processing/app/ColorChooser.java
index b4a6ccac8..b261096dd 100644
--- a/app/src/processing/app/ColorChooser.java
+++ b/app/src/processing/app/ColorChooser.java
@@ -442,6 +442,23 @@ public class ColorChooser { //extends JFrame implements DocumentListener {
row.add(Box.createHorizontalGlue());
box.add(row);
+ row = Box.createHorizontalBox();
+ if (Base.isMacOS()) {
+ row.add(Box.createHorizontalStrut(11));
+ } else {
+ row.add(createFixedLabel(""));
+ }
+ button = new JButton("Cancel");
+ button.addActionListener(new ActionListener() {
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ ColorChooser.this.hide();
+ }
+ });
+ row.add(button);
+ row.add(Box.createHorizontalGlue());
+ box.add(row);
//
box.add(Box.createVerticalGlue());
diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java
index 7f4b1a8be..90e90508e 100644
--- a/app/src/processing/app/Editor.java
+++ b/app/src/processing/app/Editor.java
@@ -33,6 +33,7 @@ import java.awt.event.*;
import java.awt.print.*;
import java.io.*;
import java.util.*;
+import java.util.List;
import java.util.Timer;
import javax.swing.*;
@@ -383,20 +384,37 @@ public abstract class Editor extends JFrame implements RunnerListener {
protected void initModeMenu() {
modeMenu = new JMenu();
+ ButtonGroup modeGroup = new ButtonGroup();
for (final Mode m : base.getModeList()) {
- if (mode == m) {
- JRadioButtonMenuItem item = new JRadioButtonMenuItem(m.getTitle());
- // doesn't need a listener, since it doesn't do anything
- item.setSelected(true);
- modeMenu.add(item);
- } else {
- JMenuItem item = new JMenuItem(m.getTitle());
- item.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
+ 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);
+ }
+ });
+ modeMenu.add(item);
+ modeGroup.add(item);
+ if (mode == m) {
+ item.setSelected(true);
}
}
@@ -588,6 +606,16 @@ public abstract class Editor extends JFrame implements RunnerListener {
fileMenu.add(item);
fileMenu.add(base.getSketchbookMenu());
+
+ JMenuItem sbMenu = Toolkit.newJMenuItemShift("Sketchbook Tree", 'K');
+ sbMenu.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ mode.showSketchbookFrame();
+ }
+ });
+
+ fileMenu.add(sbMenu);
// fileMenu.add(mode.getExamplesMenu());
item = Toolkit.newJMenuItemShift(Language.text("menu.file.examples"), 'O');
@@ -895,6 +923,57 @@ public abstract class Editor extends JFrame implements RunnerListener {
});
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;
}
@@ -1163,6 +1242,11 @@ public abstract class Editor extends JFrame implements RunnerListener {
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());
}
@@ -2369,7 +2453,10 @@ public abstract class Editor extends JFrame implements RunnerListener {
statusNotice("Saving...");
try {
if (sketch.saveAs()) {
- statusNotice("Done Saving.");
+ // statusNotice("Done Saving.");
+ // status is now printed from Sketch so that "Done Saving."
+ // is only printed after Save As when progress bar is shown.
+
// Disabling this for 0125, instead rebuild the menu inside
// the Save As method of the Sketch object, since that's the
// only one who knows whether something was renamed.
diff --git a/app/src/processing/app/EditorConsole.java b/app/src/processing/app/EditorConsole.java
index 6ad9eb709..935539841 100644
--- a/app/src/processing/app/EditorConsole.java
+++ b/app/src/processing/app/EditorConsole.java
@@ -212,7 +212,13 @@ public class EditorConsole extends JScrollPane {
StyleConstants.setBold(errStyle, font.isBold());
StyleConstants.setItalic(errStyle, font.isItalic());
- consoleTextPane.setBackground(bgColor);
+ 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
diff --git a/app/src/processing/app/Mode.java b/app/src/processing/app/Mode.java
index ea19fde35..666ec7f0d 100644
--- a/app/src/processing/app/Mode.java
+++ b/app/src/processing/app/Mode.java
@@ -879,6 +879,104 @@ public abstract class Mode {
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+ public DefaultMutableTreeNode buildSketchbookTree(){
+ DefaultMutableTreeNode sbNode = new DefaultMutableTreeNode("Sketchbook");
+ try {
+ base.addSketches(sbNode, Base.getSketchbookFolder());
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return sbNode;
+ }
+
+ protected JFrame sketchbookFrame;
+
+ public void showSketchbookFrame() {
+ if (sketchbookFrame == null) {
+ sketchbookFrame = new JFrame("Processing Sketchbook");
+ Toolkit.setIcon(sketchbookFrame);
+ Toolkit.registerWindowCloseKeys(sketchbookFrame.getRootPane(),
+ new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ sketchbookFrame.setVisible(false);
+ }
+ });
+
+ final JTree tree = new JTree(buildSketchbookTree());
+ tree.getSelectionModel()
+ .setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
+ tree.setShowsRootHandles(true);
+ tree.expandRow(0);
+ tree.setRootVisible(false);
+
+ tree.addMouseListener(new MouseAdapter() {
+ public void mouseClicked(MouseEvent e) {
+ if (e.getClickCount() == 2) {
+ DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree
+ .getLastSelectedPathComponent();
+
+ int selRow = tree.getRowForLocation(e.getX(), e.getY());
+ //TreePath selPath = tree.getPathForLocation(e.getX(), e.getY());
+ //if (node != null && node.isLeaf() && node.getPath().equals(selPath)) {
+ if (node != null && node.isLeaf() && selRow != -1) {
+ SketchReference sketch = (SketchReference) node.getUserObject();
+ base.handleOpen(sketch.getPath());
+ }
+ }
+ }
+ });
+
+ tree.addKeyListener(new KeyAdapter() {
+ public void keyPressed(KeyEvent e) {
+ if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { // doesn't fire keyTyped()
+ sketchbookFrame.setVisible(false);
+ }
+ }
+
+ public void keyTyped(KeyEvent e) {
+ if (e.getKeyChar() == KeyEvent.VK_ENTER) {
+ DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree
+ .getLastSelectedPathComponent();
+ if (node != null && node.isLeaf()) {
+ SketchReference sketch = (SketchReference) node.getUserObject();
+ base.handleOpen(sketch.getPath());
+ }
+ }
+ }
+ });
+
+ tree.setBorder(new EmptyBorder(5, 5, 5, 5));
+ if (Base.isMacOS()) {
+ tree.setToggleClickCount(2);
+ } else {
+ tree.setToggleClickCount(1);
+ }
+ JScrollPane treePane = new JScrollPane(tree);
+ treePane.setPreferredSize(new Dimension(250, 450));
+ treePane.setBorder(new EmptyBorder(0, 0, 0, 0));
+ sketchbookFrame.getContentPane().add(treePane);
+ sketchbookFrame.pack();
+ }
+
+ SwingUtilities.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ // Space for the editor plus a li'l gap
+ int roughWidth = sketchbookFrame.getWidth() + 20;
+ Point p = null;
+ // If no window open, or the editor is at the edge of the screen
+ if (base.activeEditor == null
+ || (p = base.activeEditor.getLocation()).x < roughWidth) {
+ // Center the window on the screen
+ sketchbookFrame.setLocationRelativeTo(null);
+ } else {
+ // Open the window relative to the editor
+ sketchbookFrame.setLocation(p.x - roughWidth, p.y);
+ }
+ sketchbookFrame.setVisible(true);
+ }
+ });
+ }
/**
* Get an image object from the theme folder.
diff --git a/app/src/processing/app/Preferences.java b/app/src/processing/app/Preferences.java
index 525ae5f03..06f4025a8 100644
--- a/app/src/processing/app/Preferences.java
+++ b/app/src/processing/app/Preferences.java
@@ -3,7 +3,7 @@
/*
Part of the Processing project - http://processing.org
- Copyright (c) 2004-12 Ben Fry and Casey Reas
+ Copyright (c) 2004-14 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
@@ -28,7 +28,11 @@ import java.io.*;
import java.util.*;
import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.event.*;
+import processing.app.ColorChooser;
+import processing.app.Language;
import processing.core.*;
@@ -98,7 +102,7 @@ public class Preferences {
// and linux is all over the map
static final int GUI_BIG = 13;
- static final int GUI_BETWEEN = 10;
+ static final int GUI_BETWEEN = 8;
static final int GUI_SMALL = 6;
// gui elements
@@ -107,27 +111,32 @@ public class Preferences {
int wide, high;
JTextField sketchbookLocationField;
+ JTextField presentColor;
+ JTextField presentColorHex;
JCheckBox editorAntialiasBox;
JCheckBox deletePreviousBox;
JCheckBox whinyBox;
JCheckBox memoryOverrideBox;
JTextField memoryField;
JCheckBox checkUpdatesBox;
- //JTextField fontSizeField;
JComboBox fontSizeField;
JComboBox consoleSizeField;
JCheckBox inputMethodBox;
JCheckBox autoAssociateBox;
+
+ ColorChooser selector;
- //JRadioButton bitsThirtyTwoButton;
- //JRadioButton bitsSixtyFourButton;
+ JCheckBox errorCheckerBox;
+ JCheckBox warningsCheckerBox;
+ JCheckBox codeCompletionBox;
+ JCheckBox importSuggestionsBox;
+ JCheckBox codeCompletionTriggerBox;
JComboBox displaySelectionBox;
JComboBox languageSelectionBox;
int displayCount;
- //Font[] monoFontList;
String[] monoFontFamilies;
JComboBox fontSelectionBox;
@@ -158,16 +167,6 @@ public class Preferences {
// check for platform-specific properties in the defaults
String platformExt = "." + PConstants.platformNames[PApplet.platform]; //$NON-NLS-1$
int platformExtLength = platformExt.length();
-// Enumeration e = table.keys();
-// while (e.hasMoreElements()) {
-// String key = (String) e.nextElement();
-// if (key.endsWith(platformExt)) {
-// // this is a key specific to a particular platform
-// String actualKey = key.substring(0, key.length() - platformExtLength);
-// String value = get(key);
-// table.put(actualKey, value);
-// }
-// }
// Get a list of keys that are specific to this platform
ArrayList platformKeys = new ArrayList();
@@ -190,28 +189,10 @@ public class Preferences {
// other things that have to be set explicitly for the defaults
setColor("run.window.bgcolor", SystemColor.control); //$NON-NLS-1$
-
- // Load a prefs file if specified on the command line
-// if (commandLinePrefs != null) {
-// try {
-// load(new FileInputStream(commandLinePrefs));
-//
-// } catch (Exception poe) {
-// Base.showError("Error",
-// "Could not read preferences from " +
-// commandLinePrefs, poe);
-// }
-// } else if (!Base.isCommandLine()) {
+
// next load user preferences file
preferencesFile = Base.getSettingsFile(PREFS_FILE);
- if (!preferencesFile.exists()) {
- // create a new preferences file if none exists
- // saves the defaults out to the file
- save();
-
- } else {
- // load the previous preferences file
-
+ if (preferencesFile.exists()) {
try {
load(new FileInputStream(preferencesFile));
@@ -222,7 +203,12 @@ public class Preferences {
preferencesFile.getAbsolutePath() +
" and restart Processing.", ex);
}
-// }
+ }
+
+ if (checkSketchbookPref() || !preferencesFile.exists()) {
+ // create a new preferences file if none exists
+ // saves the defaults out to the file
+ save();
}
PApplet.useNativeSelect =
@@ -247,11 +233,6 @@ public class Preferences {
dialog = new JFrame(Language.text("preferences"));
dialog.setResizable(false);
-// GroupLayout layout = new GroupLayout(getContentPane());
-// dialog.getContentPane().setLayout(layout);
-// layout.setAutoCreateGaps(true);
-// layout.setAutoCreateContainerGaps(true);
-
Container pain = dialog.getContentPane();
pain.setLayout(null);
@@ -286,11 +267,6 @@ public class Preferences {
PApplet.selectFolder(Language.text("preferences.sketchbook_location.popup"),
"sketchbookCallback", dflt,
Preferences.this, dialog);
-// File file =
-// Base.selectFolder("Select new sketchbook location", dflt, dialog);
-// if (file != null) {
-// sketchbookLocationField.setText(file.getAbsolutePath());
-// }
}
});
pain.add(button);
@@ -372,15 +348,10 @@ public class Preferences {
Container box = Box.createHorizontalBox();
label = new JLabel(Language.text("preferences.editor_font_size")+": ");
box.add(label);
- //fontSizeField = new JTextField(4);
fontSizeField = new JComboBox(FONT_SIZES);
// fontSizeField = new JComboBox(FONT_SIZES);
fontSizeField.setEditable(true);
box.add(fontSizeField);
-
-// label = new JLabel(" ("+Language.text("preferences.requires_restart")+")");
-// label = new JLabel(" (requires restart of Processing)");
-// box.add(label);
box.add(Box.createHorizontalStrut(GUI_BETWEEN));
label = new JLabel(Language.text("preferences.console_font_size")+": ");
@@ -394,19 +365,136 @@ public class Preferences {
pain.add(box);
d = box.getPreferredSize();
box.setBounds(left, top, d.width, d.height);
-// Font editorFont = Preferences.getFont("editor.font");
- //fontSizeField.setText(String.valueOf(editorFont.getSize()));
-// fontSizeField.setSelectedItem(editorFont.getSize());
fontSizeField.setSelectedItem(Preferences.getFont("editor.font.size"));
top += d.height + GUI_BETWEEN;
+ Container colorBox = Box.createHorizontalBox();
+
+ label = new JLabel("Background color when Presenting: ");
+ colorBox.add(label);
+
+ final String colorTip = ""
+ + "Select the background color used when using Present.
"
+ + "Present is used to present a sketch in full-screen,
"
+ + "accessible from the Sketch menu.";
+ label.setToolTipText(colorTip);
+
+ presentColor = new JTextField(" ");
+ presentColor.setOpaque(true);
+ presentColor.setEnabled(false);
+ presentColor.setBorder(new CompoundBorder(BorderFactory.createMatteBorder(
+ 1, 1, 0, 0, new Color(195, 195, 195)), BorderFactory.createMatteBorder(
+ 0, 0, 1, 1, new Color(54, 54, 54))));
+ presentColor.setBackground(Preferences.getColor("run.present.bgcolor"));
+
+ presentColorHex = new JTextField(6);
+ presentColorHex
+ .setText(Preferences.get("run.present.bgcolor").substring(1));
+ presentColorHex.getDocument().addDocumentListener(new DocumentListener() {
+
+ @Override
+ public void removeUpdate(DocumentEvent e) {
+ final String colorValue = presentColorHex.getText().toUpperCase();
+ if (colorValue.length() == 7 && (colorValue.startsWith("#")))
+ EventQueue.invokeLater(new Runnable() {
+ public void run() {
+ presentColorHex.setText(colorValue.substring(1));
+ }
+ });
+ if (colorValue.length() == 6
+ && colorValue.matches("[0123456789ABCDEF]*")) {
+ presentColor.setBackground(new Color(Integer.parseInt(
+ colorValue.substring(0, 2), 16), Integer.parseInt(
+ colorValue.substring(2, 4), 16), Integer.parseInt(
+ colorValue.substring(4, 6), 16)));
+ if (!colorValue.equals(presentColorHex.getText()))
+ EventQueue.invokeLater(new Runnable() {
+ public void run() {
+ presentColorHex.setText(colorValue);
+ }
+ });
+ }
+ }
+
+ @Override
+ public void insertUpdate(DocumentEvent e) {
+ final String colorValue = presentColorHex.getText().toUpperCase();
+ if (colorValue.length() == 7 && (colorValue.startsWith("#")))
+ EventQueue.invokeLater(new Runnable() {
+ public void run() {
+ presentColorHex.setText(colorValue.substring(1));
+ }
+ });
+ if (colorValue.length() == 6
+ && colorValue.matches("[0123456789ABCDEF]*")) {
+ presentColor.setBackground(new Color(Integer.parseInt(
+ colorValue.substring(0, 2), 16), Integer.parseInt(
+ colorValue.substring(2, 4), 16), Integer.parseInt(
+ colorValue.substring(4, 6), 16)));
+ if (!colorValue.equals(presentColorHex.getText()))
+ EventQueue.invokeLater(new Runnable() {
+ public void run() {
+ presentColorHex.setText(colorValue);
+ }
+ });
+ }
+ }
+
+ @Override public void changedUpdate(DocumentEvent e) {}
+ });
+
+ selector = new ColorChooser(dialog, false,
+ Preferences.getColor("run.present.bgcolor"), "OK",
+ new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ String colorValue = selector.getHexColor();
+ presentColorHex.setText(colorValue.substring(1));
+ presentColor.setBackground(new Color(Integer.parseInt(
+ colorValue.substring(1, 3), 16), Integer.parseInt(
+ colorValue.substring(3, 5), 16), Integer.parseInt(
+ colorValue.substring(5, 7), 16)));
+ selector.hide();
+ }
+ });
+
+ presentColor.addMouseListener(new MouseListener() {
+ @Override public void mouseReleased(MouseEvent e) {}
+ @Override public void mousePressed(MouseEvent e) {}
+
+ @Override
+ public void mouseExited(MouseEvent e) {
+ dialog.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
+ }
+
+ @Override
+ public void mouseEntered(MouseEvent e) {
+ dialog.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
+ }
+
+ @Override
+ public void mouseClicked(MouseEvent e) {
+ selector.show();
+ }
+ });
+
+ label = new JLabel("#");
+ colorBox.add(label);
+ colorBox.add(presentColorHex);
+ colorBox.add(Box.createHorizontalStrut(GUI_SMALL + 2 / 3 * GUI_SMALL));
+ colorBox.add(presentColor);
+
+ pain.add(colorBox);
+ d = colorBox.getPreferredSize();
+ colorBox.setBounds(left, top, d.width, d.height);
+
+ top += d.height + GUI_BETWEEN;
+
+
// [ ] Use smooth text in editor window
-
+
editorAntialiasBox = new JCheckBox(Language.text("preferences.use_smooth_text"));
-// new JCheckBox("Use smooth text in editor window " +
-// "(requires restart of Processing)");
-
pain.add(editorAntialiasBox);
d = editorAntialiasBox.getPreferredSize();
// adding +10 because ubuntu + jre 1.5 truncating items
@@ -414,7 +502,7 @@ public class Preferences {
right = Math.max(right, left + d.width);
top += d.height + GUI_BETWEEN;
-
+
// [ ] Enable complex text input (for Japanese et al, requires restart)
inputMethodBox =
@@ -426,6 +514,51 @@ public class Preferences {
inputMethodBox.setBounds(left, top, d.width + 10, d.height);
right = Math.max(right, left + d.width);
top += d.height + GUI_BETWEEN;
+
+
+ // [ ] Continuously check for errors - PDE X
+
+ errorCheckerBox =
+ new JCheckBox("Continuously check for errors");
+ pain.add(errorCheckerBox);
+ d = errorCheckerBox.getPreferredSize();
+ errorCheckerBox.setBounds(left, top, d.width + 10, d.height);
+ //right = Math.max(right, left + d.width);
+ //top += d.height + GUI_BETWEEN;
+ int warningLeft = left + d.width;
+
+
+ // [ ] Show Warnings - PDE X
+
+ warningsCheckerBox =
+ new JCheckBox("Show warnings");
+ pain.add(warningsCheckerBox);
+ d = warningsCheckerBox.getPreferredSize();
+ warningsCheckerBox.setBounds(warningLeft, top, d.width + 10, d.height);
+ right = Math.max(right, warningLeft + d.width);
+ top += d.height + GUI_BETWEEN;
+
+
+ // [ ] Enable Code Completion - PDE X
+
+ codeCompletionBox =
+ new JCheckBox("Enable code completion");
+ pain.add(codeCompletionBox);
+ d = codeCompletionBox.getPreferredSize();
+ codeCompletionBox.setBounds(left, top, d.width + 10, d.height);
+ int toggleLeft = left + d.width;
+
+
+ // [ ] Toggle Code Completion Trigger - PDE X
+
+ final String modifier = Base.isMacOS() ? "\u2318" : "Ctrl";
+ codeCompletionTriggerBox =
+ new JCheckBox("Trigger with " + modifier + "-space");
+ pain.add(codeCompletionTriggerBox);
+ d = codeCompletionTriggerBox.getPreferredSize();
+ codeCompletionTriggerBox.setBounds(toggleLeft, top, d.width + 10, d.height);
+ right = Math.max(right, toggleLeft + d.width);
+ top += d.height + GUI_BETWEEN;
// [ ] Increase maximum available memory to [______] MB
@@ -442,19 +575,6 @@ public class Preferences {
top += d.height + GUI_BETWEEN;
-// // [ ] Use multiple .jar files when exporting applets
-//
-// exportSeparateBox =
-// new JCheckBox("Use multiple .jar files when exporting applets " +
-// "(ignored when using libraries)");
-// pain.add(exportSeparateBox);
-// d = exportSeparateBox.getPreferredSize();
-// // adding +10 because ubuntu + jre 1.5 truncating items
-// exportSeparateBox.setBounds(left, top, d.width + 10, d.height);
-// right = Math.max(right, left + d.width);
-// top += d.height + GUI_BETWEEN;
-
-
// [ ] Delete previous application folder on export
deletePreviousBox =
@@ -466,17 +586,7 @@ public class Preferences {
top += d.height + GUI_BETWEEN;
-// // [ ] Use external editor
-//
-// externalEditorBox = new JCheckBox("Use external editor");
-// pain.add(externalEditorBox);
-// d = externalEditorBox.getPreferredSize();
-// externalEditorBox.setBounds(left, top, d.width + 10, d.height);
-// right = Math.max(right, left + d.width);
-// top += d.height + GUI_BETWEEN;
-
-
- // [ ] Use external editor
+ // [ ] Hide tab/toolbar background image
whinyBox = new JCheckBox(Language.text("preferences.hide_toolbar_background_image")+
" ("+Language.text("preferences.requires_restart")+")");
@@ -526,30 +636,6 @@ public class Preferences {
}
- // Launch programs as [ ] 32-bit [ ] 64-bit (Mac OS X only)
-
- /*
- if (Base.isMacOS()) {
- box = Box.createHorizontalBox();
- label = new JLabel(Language.text("preferences.launch_programs_in")+" ");
- box.add(label);
- bitsThirtyTwoButton = new JRadioButton("32-bit "+Language.text("preferences.launch_programs_in.mode")+" ");
- box.add(bitsThirtyTwoButton);
- bitsSixtyFourButton = new JRadioButton("64-bit "+Language.text("preferences.launch_programs_in.mode"));
- box.add(bitsSixtyFourButton);
-
- ButtonGroup bg = new ButtonGroup();
- bg.add(bitsThirtyTwoButton);
- bg.add(bitsSixtyFourButton);
-
- pain.add(box);
- d = box.getPreferredSize();
- box.setBounds(left, top, d.width, d.height);
- top += d.height + GUI_BETWEEN;
- }
- */
-
-
// More preferences are in the ...
label = new JLabel(Language.text("preferences.file")+":");
@@ -708,7 +794,7 @@ public class Preferences {
// each platform, and nobody wants to debug/support that.
// if the sketchbook path has changed, rebuild the menus
- String oldPath = get("sketchbook.path"); //$NON-NLS-1$
+ String oldPath = getSketchbookPath();
String newPath = sketchbookLocationField.getText();
if (!newPath.equals(oldPath)) {
base.setSketchbookFolder(new File(newPath));
@@ -756,52 +842,12 @@ public class Preferences {
System.err.println("Ignoring bad memory setting");
}
- /*
- // was gonna use this to check memory settings,
- // but it quickly gets much too messy
- if (getBoolean("run.options.memory")) {
- Process process = Runtime.getRuntime().exec(new String[] {
- "java", "-Xms" + memoryMin + "m", "-Xmx" + memoryMax + "m"
- });
- processInput = new SystemOutSiphon(process.getInputStream());
- processError = new MessageSiphon(process.getErrorStream(), this);
- }
- */
-
- /*
- // If a change has been made between 32- and 64-bit, the libraries need
- // to be reloaded so that their native paths are set correctly.
- if (Base.isMacOS()) {
- String oldBits = get("run.options.bits"); //$NON-NLS-1$
- String newBits = bitsThirtyTwoButton.isSelected() ? "32" : "64"; //$NON-NLS-1$ //$NON-NLS-2$
- if (!oldBits.equals(newBits)) {
- set("run.options.bits", newBits); //$NON-NLS-1$
- for (Mode m : base.getModeList()) {
- m.rebuildLibraryList();
- }
- }
- }
- */
-
// Don't change anything if the user closes the window before fonts load
if (fontSelectionBox.isEnabled()) {
String fontFamily = (String) fontSelectionBox.getSelectedItem();
set("editor.font.family", fontFamily);
}
- /*
- String newSizeText = fontSizeField.getText();
- try {
- int newSize = Integer.parseInt(newSizeText.trim());
- //String pieces[] = PApplet.split(get("editor.font"), ','); //$NON-NLS-1$
- //pieces[2] = String.valueOf(newSize);
- //set("editor.font", PApplet.join(pieces, ',')); //$NON-NLS-1$
- set("editor.font.size", String.valueOf(newSize));
-
- } catch (Exception e) {
- Base.log("Ignoring invalid font size " + newSizeText); //$NON-NLS-1$
- }
- */
try {
Object selection = fontSizeField.getSelectedItem();
if (selection instanceof String) {
@@ -828,51 +874,45 @@ public class Preferences {
consoleSizeField.setSelectedItem(getInteger("console.font.size"));
}
+ setColor("run.present.bgcolor", presentColor.getBackground());
+
setBoolean("editor.input_method_support", inputMethodBox.isSelected()); //$NON-NLS-1$
if (autoAssociateBox != null) {
setBoolean("platform.auto_file_type_associations", //$NON-NLS-1$
autoAssociateBox.isSelected());
}
-
+
+ setBoolean("pdex.errorCheckEnabled", errorCheckerBox.isSelected());
+ setBoolean("pdex.warningsEnabled", warningsCheckerBox.isSelected());
+ setBoolean("pdex.ccEnabled", codeCompletionBox.isSelected());
+ setBoolean("pdex.ccTriggerEnabled", codeCompletionTriggerBox.isSelected());
for (Editor editor : base.getEditors()) {
editor.applyPreferences();
}
+
}
protected void showFrame() {
editorAntialiasBox.setSelected(getBoolean("editor.smooth")); //$NON-NLS-1$
inputMethodBox.setSelected(getBoolean("editor.input_method_support")); //$NON-NLS-1$
-
- // set all settings entry boxes to their actual status
-// exportSeparateBox.
-// setSelected(getBoolean("export.applet.separate_jar_files"));
+ errorCheckerBox.setSelected(getBoolean("pdex.errorCheckEnabled"));
+ warningsCheckerBox.setSelected(getBoolean("pdex.warningsEnabled"));
+ codeCompletionBox.setSelected(getBoolean("pdex.ccEnabled"));
+ codeCompletionTriggerBox.setSelected(getBoolean("pdex.ccTriggerEnabled"));
deletePreviousBox.
setSelected(getBoolean("export.delete_target_folder")); //$NON-NLS-1$
- //closingLastQuitsBox.
- // setSelected(getBoolean("sketchbook.closing_last_window_quits"));
- //sketchPromptBox.
- // setSelected(getBoolean("sketchbook.prompt"));
- //sketchCleanBox.
- // setSelected(getBoolean("sketchbook.auto_clean"));
-
- sketchbookLocationField.
- setText(get("sketchbook.path")); //$NON-NLS-1$
-// externalEditorBox.
-// setSelected(getBoolean("editor.external"));
- checkUpdatesBox.
- setSelected(getBoolean("update.check")); //$NON-NLS-1$
+ sketchbookLocationField.setText(getSketchbookPath());
+ checkUpdatesBox.setSelected(getBoolean("update.check")); //$NON-NLS-1$
whinyBox.setSelected(getBoolean("header.hide.image") || //$NON-NLS-1$
getBoolean("buttons.hide.image")); //$NON-NLS-1$
updateDisplayList();
int displayNum = getInteger("run.display"); //$NON-NLS-1$
-// System.out.println("display is " + displayNum + ", d count is " + displayCount);
if (displayNum >= 0 && displayNum < displayCount) {
-// System.out.println("setting num to " + displayNum);
displaySelectionBox.setSelectedIndex(displayNum);
}
@@ -886,27 +926,14 @@ public class Preferences {
fontSizeField.setSelectedItem(getInteger("editor.font.size"));
consoleSizeField.setSelectedItem(getInteger("console.font.size"));
+ presentColor.setBackground(Preferences.getColor("run.present.bgcolor"));
+ presentColorHex.setText(Preferences.get("run.present.bgcolor").substring(1));
+
memoryOverrideBox.
setSelected(getBoolean("run.options.memory")); //$NON-NLS-1$
memoryField.
setText(get("run.options.memory.maximum")); //$NON-NLS-1$
- /*
- if (Base.isMacOS()) {
- String bits = Preferences.get("run.options.bits"); //$NON-NLS-1$
- if (bits.equals("32")) { //$NON-NLS-1$
- bitsThirtyTwoButton.setSelected(true);
- } else if (bits.equals("64")) { //$NON-NLS-1$
- bitsSixtyFourButton.setSelected(true);
- }
- // in case we go back and support OS X 10.5...
- if (System.getProperty("os.version").startsWith("10.5")) { //$NON-NLS-1$ //$NON-NLS-2$
- bitsSixtyFourButton.setSelected(true);
- bitsThirtyTwoButton.setEnabled(false);
- }
- }
- */
-
if (autoAssociateBox != null) {
autoAssociateBox.
setSelected(getBoolean("platform.auto_file_type_associations")); //$NON-NLS-1$
@@ -934,37 +961,11 @@ public class Preferences {
void initFontList() {
- /*
- if (monoFontList == null) {
- monoFontList = Toolkit.getMonoFontList().toArray(new Font[0]);
- fontSelectionBox.setModel(new DefaultComboBoxModel(monoFontList));
- fontSelectionBox.setRenderer(new FontNamer());
-
- // Preferred size just makes it extend to the container
- //fontSelectionBox.setSize(fontSelectionBox.getPreferredSize());
- // Minimum size is better, but cuts things off (on OS X), so we add 20
- //Dimension minSize = fontSelectionBox.getMinimumSize();
- //Dimension minSize = fontSelectionBox.getPreferredSize();
- //fontSelectionBox.setSize(minSize.width + 20, minSize.height);
- fontSelectionBox.setEnabled(true);
- }
- */
if (monoFontFamilies == null) {
monoFontFamilies = Toolkit.getMonoFontFamilies();
fontSelectionBox.setModel(new DefaultComboBoxModel(monoFontFamilies));
String family = get("editor.font.family");
-// System.out.println("family is " + family);
-// System.out.println("font sel items = " + fontSelectionBox.getItemCount());
-// for (int i = 0; i < fontSelectionBox.getItemCount(); i++) {
-// String item = (String) fontSelectionBox.getItemAt(i);
-// if (fontSelectionBox.getItemAt(i) == family) {
-// System.out.println("found at index " + i);
-// } else if (item.equals(family)) {
-// System.out.println("equals at index " + i);
-// } else {
-// System.out.println("nothing doing: " + item);
-// }
-// }
+
// Set a reasonable default, in case selecting the family fails
fontSelectionBox.setSelectedItem("Monospaced");
fontSelectionBox.setSelectedItem(family);
@@ -988,22 +989,6 @@ public class Preferences {
}
- // Workaround for Apple bullsh*t caused by their not releasing a 32-bit
- // version of Java for Mac OS X 10.5.
-// static public String checkBits() {
-// String bits = Preferences.get("run.options.bits");
-// if (bits == null) {
-// if (System.getProperty("os.version").startsWith("10.5")) {
-// bits = "64";
-// } else {
-// bits = "32";
-// }
-// Preferences.set("run.options.bits", bits);
-// }
-// return bits;
-// }
-
-
// .................................................................
@@ -1062,20 +1047,8 @@ public class Preferences {
// all the information from preferences.txt
- //static public String get(String attribute) {
- //return get(attribute, null);
- //}
-
static public String get(String attribute /*, String defaultValue */) {
return table.get(attribute);
- /*
- //String value = (properties != null) ?
- //properties.getProperty(attribute) : applet.getParameter(attribute);
- String value = properties.getProperty(attribute);
-
- return (value == null) ?
- defaultValue : value;
- */
}
@@ -1213,28 +1186,37 @@ public class Preferences {
}
return new Font("Dialog", Font.PLAIN, 12);
}
+
+
+ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+
-
- /*
- static public SyntaxStyle getStyle(String what) {
- String str = get("editor." + what + ".style"); //, dflt); //$NON-NLS-1$ //$NON-NLS-2$
-
- StringTokenizer st = new StringTokenizer(str, ","); //$NON-NLS-1$
-
- String s = st.nextToken();
- if (s.indexOf("#") == 0) s = s.substring(1); //$NON-NLS-1$
- Color color = Color.DARK_GRAY;
- try {
- color = new Color(Integer.parseInt(s, 16));
- } catch (Exception e) { }
-
- s = st.nextToken();
- boolean bold = (s.indexOf("bold") != -1); //$NON-NLS-1$
-// boolean italic = (s.indexOf("italic") != -1); //$NON-NLS-1$
- //System.out.println(what + " = " + str + " " + bold + " " + italic);
-
-// return new SyntaxStyle(color, italic, bold);
- return new SyntaxStyle(color, bold);
+ /**
+ * Check for a 3.0 sketchbook location, and if none exists,
+ * try to grab it from the 2.0 sketchbook location.
+ * @return true if a location was found and the pref didn't exist
+ */
+ static protected boolean checkSketchbookPref() {
+ // If a 3.0 sketchbook location has never been inited
+ if (getSketchbookPath() == null) {
+ String twoPath = get("sketchbook.path");
+ // If they've run the 2.0 version, start with that location
+ if (twoPath != null) {
+ setSketchbookPath(twoPath);
+ return true; // save the sketchbook right away
+ }
+ // Otherwise it'll be null, and reset properly by Base
+ }
+ return false;
+ }
+
+
+ static protected String getSketchbookPath() {
+ return get("sketchbook.path.three"); //$NON-NLS-1$
+ }
+
+
+ static protected void setSketchbookPath(String path) {
+ set("sketchbook.path.three", path); //$NON-NLS-1$
}
- */
}
diff --git a/app/src/processing/app/ProgressFrame.java b/app/src/processing/app/ProgressFrame.java
new file mode 100644
index 000000000..3e91ee54c
--- /dev/null
+++ b/app/src/processing/app/ProgressFrame.java
@@ -0,0 +1,379 @@
+package processing.app;
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JProgressBar;
+import javax.swing.SwingWorker;
+
+//Class used to handle progress bar, and run Save As or Add File in
+//background so that
+//progress bar can update without freezing
+public class ProgressFrame extends JFrame implements PropertyChangeListener {
+
+ private static final long serialVersionUID = 1L;
+
+ private JProgressBar progressBar;
+
+ private JLabel saveAsLabel;
+
+ private TaskSaveAs t;
+
+ private TaskAddFile t2;
+
+ private File[] copyItems;
+
+ private File newFolder;
+
+ private File addFile, sourceFile;
+
+ private Editor editor;
+
+ // create a new background thread to save as
+ public class TaskSaveAs extends SwingWorker {
+
+ @Override
+ protected Void doInBackground() throws Exception {
+ // a large part of the file copying happens in this background
+ // thread
+
+ long totalSize = 0;
+ for (File copyable : copyItems) {
+ totalSize += getFileLength(copyable);
+ }
+
+ long progress = 0;
+ setProgress(0);
+ for (File copyable : ProgressFrame.this.copyItems) {
+ // loop to copy over the items that make sense, and to set the
+ // current progress
+
+ if (copyable.isDirectory()) {
+ copyDir(copyable,
+ new File(ProgressFrame.this.newFolder, copyable.getName()),
+ this, progress, totalSize);
+ progress += getFileLength(copyable);
+ } else {
+ copyFile(copyable,
+ new File(ProgressFrame.this.newFolder, copyable.getName()),
+ this, progress, totalSize);
+ if (getFileLength(copyable) < 524288) {
+ // If the file length > 0.5MB, the copyFile() function has
+ // been redesigned to change progress every 0.5MB so that
+ // the progress bar doesn't stagnate during that time
+ progress += getFileLength(copyable);
+ setProgress((int) Math.min(Math.ceil(progress * 100.0 / totalSize),
+ 100));
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public void setProgressBarStatus(int status) {
+
+ setProgress(status);
+ }
+
+ @Override
+ public void done() {
+ // to close the progress bar automatically when done, and to
+ // print that Saving is done in Message Area
+
+ editor.statusNotice("Done Saving.");
+ ProgressFrame.this.closeProgressBar();
+ }
+
+ }
+
+ // create a new background thread to add a file
+ public class TaskAddFile extends SwingWorker {
+
+ @Override
+ protected Void doInBackground() throws Exception {
+ // a large part of the file copying happens in this background
+ // thread
+
+ setProgress(0);
+
+ copyFile(sourceFile, addFile, this);
+
+ if (addFile.length() < 1024) {
+ // If the file length > 1kB, the copyFile() function has
+ // been redesigned to change progress every 1kB so that
+ // the progress bar doesn't stagnate during that time
+
+ // If file <1 kB, just fill up Progress Bar to 100%
+ // directly, since time to copy is now negligable (when
+ // perceived by a human, anyway)
+ setProgress(100);
+ }
+
+ return null;
+ }
+
+ public void setProgressBarStatus(int status) {
+ setProgress(status);
+ }
+
+ @Override
+ public void done() {
+ // to close the progress bar automatically when done, and to
+ // print that adding file is done in Message Area
+
+ editor.statusNotice("One file added to the sketch.");
+ ProgressFrame.this.closeProgressBar();
+ }
+
+ }
+
+ //Use for Save As
+ public ProgressFrame(File[] c, File nf, String oldName, String newName,
+ Editor editor) {
+ // initialize a copyItems and newFolder, which are used for file
+ // copying in the background thread
+ copyItems = c;
+ newFolder = nf;
+ this.editor = editor;
+
+ // the UI of the progress bar follows
+ setDefaultCloseOperation(HIDE_ON_CLOSE);
+ setBounds(200, 200, 400, 140);
+ setResizable(false);
+ setTitle("Saving As...");
+ JPanel panel = new JPanel(null);
+ add(panel);
+ setContentPane(panel);
+ saveAsLabel = new JLabel("Saving " + oldName + " as " + newName + "...");
+ saveAsLabel.setBounds(40, 20, 300, 20);
+
+ progressBar = new JProgressBar(0, 100);
+ progressBar.setValue(0);
+ progressBar.setBounds(40, 50, 300, 30);
+ progressBar.setStringPainted(true);
+
+ panel.add(progressBar);
+ panel.add(saveAsLabel);
+ Toolkit.setIcon(this);
+ this.setVisible(true);
+
+ // create an instance of TaskSaveAs and run execute() on this
+ // instance to
+ // start background thread
+ t = new TaskSaveAs();
+ t.addPropertyChangeListener(this);
+ t.execute();
+ }
+
+ //Use for Add File
+ public ProgressFrame(File sf, File add, Editor editor) {
+
+ addFile = add;
+ sourceFile = sf;
+ this.editor = editor;
+
+ // the UI of the progress bar follows
+ setDefaultCloseOperation(HIDE_ON_CLOSE);
+ setBounds(200, 200, 400, 140);
+ setResizable(false);
+ setTitle("Adding File...");
+ JPanel panel = new JPanel(null);
+ add(panel);
+ setContentPane(panel);
+ saveAsLabel = new JLabel("Adding " + addFile.getName());
+ saveAsLabel.setBounds(40, 20, 300, 20);
+
+ progressBar = new JProgressBar(0, 100);
+ progressBar.setValue(0);
+ progressBar.setBounds(40, 50, 300, 30);
+ progressBar.setStringPainted(true);
+
+ panel.add(progressBar);
+ panel.add(saveAsLabel);
+ Toolkit.setIcon(this);
+ this.setVisible(true);
+
+ // create an instance of TaskAddFile and run execute() on this
+ // instance to
+ // start background thread
+ t2 = new TaskAddFile();
+ t2.addPropertyChangeListener(this);
+ t2.execute();
+ }
+
+ public long getFileLength(File f)// function to return the length of
+ // the file, or
+ // ENTIRE directory, including the
+ // component files
+ // and sub-folders if passed
+ {
+ long fol_len = 0;
+ if (f.isDirectory()) {
+ String files[] = f.list();
+ for (int i = 0; i < files.length; i++) {
+ File temp = new File(f, files[i]);
+ if (temp.isDirectory()) {
+ fol_len += getFileLength(temp);
+ } else {
+ fol_len += (temp.length());
+ }
+ }
+ } else {
+ return (f.length());
+ }
+ return fol_len;
+ }
+
+ public void propertyChange(PropertyChangeEvent evt)
+ // detects a change in the property of the background task, i.e., is
+ // called when the size of files already copied changes
+ {
+ if ("progress" == evt.getPropertyName()) {
+ int progress = (Integer) evt.getNewValue();
+ progressBar.setValue(progress);
+ }
+ }
+
+ private void closeProgressBar()
+ // closes progress bar
+ {
+ this.dispose();
+ }
+
+ static public void copyFile(File sourceFile, File targetFile,
+ ProgressFrame.TaskSaveAs progBar,
+ double progress, double totalSize)
+ throws IOException {
+ // Overloaded copyFile that is called whenever a Save As is being done, so that the
+ // ProgressBar is updated for very large files as well
+ BufferedInputStream from = new BufferedInputStream(
+ new FileInputStream(
+ sourceFile));
+ BufferedOutputStream to = new BufferedOutputStream(
+ new FileOutputStream(
+ targetFile));
+ byte[] buffer = new byte[16 * 1024];
+ int bytesRead;
+ int totalRead = 0;
+ while ((bytesRead = from.read(buffer)) != -1) {
+ to.write(buffer, 0, bytesRead);
+ totalRead += bytesRead;
+ if (totalRead >= 524288) //to update progress bar every 0.5MB
+ {
+ progress += totalRead;
+ progBar.setProgressBarStatus((int) Math.min(Math.ceil(progress * 100.0
+ / totalSize), 100));
+ totalRead = 0;
+ }
+ }
+ if (sourceFile.length() > 524288) {
+ // Update the progress bar one final time if file size is more than 0.5MB,
+ // otherwise, the update is handled either by the copyDir function,
+ // or directly by ProgressFrame.TaskSaveAs.doInBackground()
+ progress += totalRead;
+ progBar.setProgressBarStatus((int) Math.min(Math.ceil(progress * 100.0
+ / totalSize), 100));
+ }
+ from.close();
+ from = null;
+ to.flush();
+ to.close();
+ to = null;
+
+ targetFile.setLastModified(sourceFile.lastModified());
+ targetFile.setExecutable(sourceFile.canExecute());
+ }
+
+ static public void copyFile(File sourceFile, File targetFile,
+ ProgressFrame.TaskAddFile progBar)
+ throws IOException {
+ // Overloaded copyFile that is called whenever a addFile is being done,
+ // so that the
+ // ProgressBar is updated
+ double totalSize = sourceFile.length();
+ int progress = 0;
+ BufferedInputStream from = new BufferedInputStream(
+ new FileInputStream(
+ sourceFile));
+ BufferedOutputStream to = new BufferedOutputStream(
+ new FileOutputStream(
+ targetFile));
+ byte[] buffer = new byte[16 * 1024];
+ int bytesRead;
+ int totalRead = 0;
+ while ((bytesRead = from.read(buffer)) != -1) {
+ to.write(buffer, 0, bytesRead);
+ totalRead += bytesRead;
+ if (totalRead >= 1024) // to update progress bar every 1kB
+ {
+ progress += totalRead;
+ progBar.setProgressBarStatus((int) Math.min(Math.ceil(progress * 100.0
+ / totalSize), 100));
+ totalRead = 0;
+ }
+ }
+ if (sourceFile.length() > 1024) {
+ // Update the progress bar one final time if file size is more than
+ // 1kB,
+ // otherwise, the update is handled directly by
+ // ProgressFrame.TaskAddFile.doInBackground()
+ progress += totalRead;
+ progBar.setProgressBarStatus((int) Math.min(Math.ceil(progress * 100.0
+ / totalSize), 100));
+ }
+ from.close();
+ from = null;
+ to.flush();
+ to.close();
+ to = null;
+ targetFile.setLastModified(sourceFile.lastModified());
+ targetFile.setExecutable(sourceFile.canExecute());
+ }
+
+ static public double copyDir(File sourceDir, File targetDir,
+ ProgressFrame.TaskSaveAs progBar,
+ double progress, double totalSize)
+ throws IOException {
+ // Overloaded copyDir so that the Save As progress bar gets updated when the
+ // files are in folders as well (like in the data folder)
+ 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();
+ progress = copyDir(source, target, progBar, progress, totalSize);
+ progBar.setProgressBarStatus((int) Math.min(Math.ceil(progress * 100.0
+ / totalSize), 100));
+ target.setLastModified(source.lastModified());
+ } else {
+ copyFile(source, target, progBar, progress, totalSize);
+ // Update SaveAs progress bar
+ progress += source.length();
+ progBar.setProgressBarStatus((int) Math.min(Math.ceil(progress * 100.0
+ / totalSize), 100));
+ }
+ }
+ return progress;
+ }
+
+}
diff --git a/app/src/processing/app/Sketch.java b/app/src/processing/app/Sketch.java
index 41cb57482..d0a644c7c 100644
--- a/app/src/processing/app/Sketch.java
+++ b/app/src/processing/app/Sketch.java
@@ -26,6 +26,9 @@ package processing.app;
import processing.core.*;
import java.awt.*;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
import java.io.*;
import javax.swing.*;
@@ -286,7 +289,8 @@ public class Sketch {
}
renamingCode = false;
- editor.status.edit("Name for new file:", "");
+ // editor.status.edit("Name for new file:", "");
+ promptForTabName("Name for new file:", "");
}
@@ -326,8 +330,94 @@ public class Sketch {
"New name for sketch:" : "New name for file:";
String oldName = (current.isExtension(mode.getDefaultExtension())) ?
current.getPrettyName() : current.getFileName();
- editor.status.edit(prompt, oldName);
+ // editor.status.edit(prompt, oldName);
+ promptForTabName(prompt, oldName);
}
+
+ /**
+ * Displays a dialog for renaming or creating a new tab
+ * @param prompt - msg to display
+ * @param oldName
+ */
+ protected void promptForTabName(String prompt, String oldName) {
+ final JTextField field = new JTextField(oldName);
+
+ field.addKeyListener(new KeyAdapter() {
+ // Forget ESC, the JDialog should handle it.
+ // 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);
+ char ch = event.getKeyChar();
+ if ((ch == '_') || (ch == '.') || // allow.pde and .java
+ (('A' <= ch) && (ch <= 'Z')) || (('a' <= ch) && (ch <= 'z'))) {
+ // These events are allowed straight through.
+ } else if (ch == ' ') {
+ String t = field.getText();
+ int start = field.getSelectionStart();
+ int end = field.getSelectionEnd();
+ field.setText(t.substring(0, start) + "_" + t.substring(end));
+ field.setCaretPosition(start + 1);
+ event.consume();
+ } else if ((ch >= '0') && (ch <= '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 (field.getCaretPosition() == 0 ||
+ field.getSelectionStart() == 0) {
+ // number not allowed as first digit
+ event.consume();
+ }
+ } else if (ch == KeyEvent.VK_ENTER) {
+ // Slightly ugly hack that ensures OK button of the dialog consumes
+ // the Enter key event. Since the text field is the default component
+ // in the dialog, OK doesn't consume Enter key event, by default.
+ Container parent = field.getParent();
+ while (!(parent instanceof JOptionPane)) {
+ parent = parent.getParent();
+ }
+ JOptionPane pane = (JOptionPane) parent;
+ final JPanel pnlBottom = (JPanel)
+ pane.getComponent(pane.getComponentCount() - 1);
+ for (int i = 0; i < pnlBottom.getComponents().length; i++) {
+ Component component = pnlBottom.getComponents()[i];
+ if (component instanceof JButton) {
+ final JButton okButton = (JButton) component;
+ if (okButton.getText().equalsIgnoreCase("OK")) {
+ ActionListener[] actionListeners =
+ okButton.getActionListeners();
+ if (actionListeners.length > 0) {
+ actionListeners[0].actionPerformed(null);
+ event.consume();
+ }
+ }
+ }
+ }
+ } else {
+ event.consume();
+ }
+ }
+ });
+
+ int userReply = JOptionPane.showOptionDialog(editor, new Object[] {
+ prompt, field },
+ "New Name",
+ JOptionPane.OK_CANCEL_OPTION,
+ JOptionPane.PLAIN_MESSAGE,
+ null, new Object[] {
+ Preferences.PROMPT_OK,
+ Preferences.PROMPT_CANCEL },
+ field);
+
+ if (userReply == JOptionPane.OK_OPTION) {
+ nameCode(field.getText());
+ }
+ }
+
/**
@@ -382,7 +472,7 @@ public class Sketch {
if (current == code[0]) { // If this is the main tab, disallow
Base.showWarning("Problem with rename",
"The first tab cannot be a ." + newExtension + " file.\n" +
- "(It may be time for your to graduate to a\n" +
+ "(It may be time for you to graduate to a\n" +
"\"real\" programming environment, hotshot.)");
return;
}
@@ -654,7 +744,8 @@ public class Sketch {
if (Base.isMacOS()) {
// http://developer.apple.com/qa/qa2001/qa1146.html
Object modifiedParam = modified ? Boolean.TRUE : Boolean.FALSE;
- editor.getRootPane().putClientProperty("windowModified", modifiedParam);
+ // https://developer.apple.com/library/mac/technotes/tn2007/tn2196.html#WINDOW_DOCUMENTMODIFIED
+ editor.getRootPane().putClientProperty("Window.documentModified", modifiedParam);
}
}
@@ -712,6 +803,8 @@ public class Sketch {
protected boolean saveAs() throws IOException {
String newParentDir = null;
String newName = null;
+
+ final String oldName2 = folder.getName();
// TODO rewrite this to use shared version from PApplet
final String PROMPT = Language.text("save");
if (Preferences.getBoolean("chooser.files.native")) {
@@ -719,7 +812,7 @@ public class Sketch {
FileDialog fd = new FileDialog(editor, PROMPT, FileDialog.SAVE);
if (isReadOnly() || isUntitled()) {
// default to the sketchbook folder
- fd.setDirectory(Preferences.get("sketchbook.path"));
+ fd.setDirectory(Preferences.getSketchbookPath());
} else {
// default to the parent folder of where this was
fd.setDirectory(folder.getParent());
@@ -734,7 +827,7 @@ public class Sketch {
fc.setDialogTitle(PROMPT);
if (isReadOnly() || isUntitled()) {
// default to the sketchbook folder
- fc.setCurrentDirectory(new File(Preferences.get("sketchbook.path")));
+ fc.setCurrentDirectory(new File(Preferences.getSketchbookPath()));
} else {
// default to the parent folder of where this was
fc.setCurrentDirectory(folder.getParentFile());
@@ -846,15 +939,21 @@ public class Sketch {
return true;
}
});
- // now copy over the items that make sense
- for (File copyable : copyItems) {
- if (copyable.isDirectory()) {
- Base.copyDir(copyable, new File(newFolder, copyable.getName()));
- } else {
- Base.copyFile(copyable, new File(newFolder, copyable.getName()));
- }
- }
+
+ final File newFolder2 = newFolder;
+ final File[] copyItems2 = copyItems;
+ final String newName2 = newName;
+
+ // Create a new event dispatch thread- to display ProgressBar
+ // while Saving As
+ javax.swing.SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ new ProgressFrame(copyItems2, newFolder2, oldName2, newName2, editor);
+ }
+ });
+
+
// save the other tabs to their new location
for (int i = 1; i < codeCount; i++) {
File newFile = new File(newFolder, code[i].getFileName());
@@ -885,6 +984,7 @@ public class Sketch {
}
+
/**
* Update internal state for new sketch name or folder location.
*/
@@ -950,7 +1050,8 @@ public class Sketch {
boolean result = addFile(sourceFile);
if (result) {
- editor.statusNotice("One file added to the sketch.");
+// editor.statusNotice("One file added to the sketch.");
+ //Done from within TaskAddFile inner class when copying is completed
}
}
@@ -1043,16 +1144,17 @@ public class Sketch {
// in case the user is "adding" the code in an attempt
// to update the sketch's tabs
- if (!sourceFile.equals(destFile)) {
- try {
- Base.copyFile(sourceFile, destFile);
-
- } catch (IOException e) {
- Base.showWarning("Error adding file",
- "Could not add '" + filename + "' to the sketch.", e);
- return false;
+ if (!sourceFile.equals(destFile)) {
+ final File sourceFile2 = sourceFile;
+ final File destFile2 = destFile;
+ // Create a new event dispatch thread- to display ProgressBar
+ // while Saving As
+ javax.swing.SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ new ProgressFrame(sourceFile2, destFile2, editor);
}
- }
+ });
+ }
if (codeExtension != null) {
SketchCode newCode = new SketchCode(destFile, codeExtension);
@@ -1286,7 +1388,6 @@ public class Sketch {
*/
public String getMainFilePath() {
return primaryFile.getAbsolutePath();
- //return code[0].file.getAbsolutePath();
}
diff --git a/app/src/processing/app/Toolkit.java b/app/src/processing/app/Toolkit.java
index 34aa23834..83ead7661 100644
--- a/app/src/processing/app/Toolkit.java
+++ b/app/src/processing/app/Toolkit.java
@@ -40,8 +40,8 @@ import java.awt.font.TextLayout;
import java.awt.geom.AffineTransform;
import java.io.BufferedInputStream;
import java.io.File;
+import java.io.FileInputStream;
import java.io.IOException;
-import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashSet;
@@ -453,9 +453,16 @@ public class Toolkit {
}
+ /**
+ * Get a font from the JRE lib/fonts folder. Our default fonts are also
+ * installed there so that the monospace (and others) can be used by other
+ * font listing calls (i.e. it appears in the list of monospace fonts in
+ * the Preferences window).
+ */
static private Font createFont(String filename, int size) throws IOException, FontFormatException {
- InputStream is = Base.getLibStream("fonts/" + filename);
- BufferedInputStream input = new BufferedInputStream(is);
+ //InputStream is = Base.getLibStream("fonts/" + filename);
+ File fontFile = new File(System.getProperty("java.home"), "lib/fonts/" + filename);
+ BufferedInputStream input = new BufferedInputStream(new FileInputStream(fontFile));
Font font = Font.createFont(Font.TRUETYPE_FONT, input);
input.close();
return font.deriveFont((float) size);
diff --git a/app/src/processing/app/UpdateCheck.java b/app/src/processing/app/UpdateCheck.java
index fe98fab2b..c1a3cb4d5 100644
--- a/app/src/processing/app/UpdateCheck.java
+++ b/app/src/processing/app/UpdateCheck.java
@@ -58,7 +58,7 @@ public class UpdateCheck {
new Thread(new Runnable() {
public void run() {
try {
- Thread.sleep(30 * 1000); // give the PDE time to get rolling
+ Thread.sleep(20 * 1000); // give the PDE time to get rolling
updateCheck();
} catch (Exception e) {
// this can safely be ignored, too many instances where no net
@@ -124,11 +124,11 @@ public class UpdateCheck {
// (this should really be handled better).
Thread.sleep(5 * 1000);
if ((!base.libraryManagerFrame.hasAlreadyBeenOpened() &&
- base.libraryManagerFrame.hasUpdates()) ||
+ base.libraryManagerFrame.hasUpdates(base)) ||
(!base.toolManagerFrame.hasAlreadyBeenOpened() &&
- base.toolManagerFrame.hasUpdates()) ||
+ base.toolManagerFrame.hasUpdates(base)) ||
(!base.modeManagerFrame.hasAlreadyBeenOpened() &&
- base.modeManagerFrame.hasUpdates())) {
+ base.modeManagerFrame.hasUpdates(base))) {
promptToOpenContributionManager();
}
}
diff --git a/app/src/processing/app/contrib/AvailableContribution.java b/app/src/processing/app/contrib/AvailableContribution.java
index a815ab6da..44ed86888 100644
--- a/app/src/processing/app/contrib/AvailableContribution.java
+++ b/app/src/processing/app/contrib/AvailableContribution.java
@@ -1,4 +1,4 @@
-/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Part of the Processing project - http://processing.org
@@ -23,6 +23,7 @@ package processing.app.contrib;
import java.io.*;
import java.util.HashMap;
+import java.util.List;
import processing.app.Base;
import processing.app.Editor;
@@ -53,6 +54,13 @@ class AvailableContribution extends Contribution {
version = PApplet.parseInt(versionStr, 0);
}
prettyVersion = params.get("prettyVersion");
+ String lastUpdatedStr = params.get("lastUpdated");
+ if (lastUpdatedStr != null)
+ try {
+ lastUpdated = Long.parseLong(lastUpdatedStr);
+ } catch (NumberFormatException e) {
+ lastUpdated = 0;
+ }
}
@@ -179,26 +187,96 @@ class AvailableContribution extends Contribution {
/**
- * We overwrite the properties file with the curated version from the
- * Processing site. This ensures that things have been cleaned up (for
- * instance, that the "sentence" is really a sentence) and that bad data
- * from the contrib's .properties file doesn't break the manager.
+ * We overwrite those fields that aren't proper in the properties file with
+ * the curated version from the Processing site. This ensures that things have
+ * been cleaned up (for instance, that the "sentence" is really a sentence)
+ * and that bad data from the contrib's .properties file doesn't break the
+ * manager. However, it also ensures that valid fields in the properties file
+ * aren't overwritten, since the properties file may be more recent than the
+ * contributions.txt file.
+ *
* @param propFile
* @return
*/
public boolean writePropertiesFile(File propFile) {
try {
+
+ HashMap properties = Base.readSettings(propFile);
+
+ String name = properties.get("name");
+ if (name == null || name.isEmpty())
+ name = getName();
+
+ String category;
+ List categoryList = parseCategories(properties.get("category"));
+ if (categoryList.size() == 1 && categoryList.get(0).equals("Unknown"))
+ category = getCategoryStr();
+ else {
+ StringBuilder sb = new StringBuilder();
+ for (String cat : categories) {
+ sb.append(cat);
+ sb.append(',');
+ }
+ sb.deleteCharAt(sb.length() - 1);
+ category = sb.toString();
+ }
+
+ String authorList = properties.get("authorList");
+ if (authorList == null || authorList.isEmpty())
+ authorList = getAuthorList();
+
+ String url = properties.get("url");
+ if (url == null || url.isEmpty())
+ url = getUrl();
+
+ String sentence = properties.get("sentence");
+ if (sentence == null || sentence.isEmpty())
+ sentence = getSentence();
+
+ String paragraph = properties.get("paragraph");
+ if (paragraph == null || paragraph.isEmpty())
+ paragraph = getParagraph();
+
+ int version;
+ try {
+ version = Integer.parseInt(properties.get("version"));
+ } catch (NumberFormatException e) {
+ version = getVersion();
+ System.err.println("The version number for the “" + name
+ + "” contribution is not set properly.");
+ System.err
+ .println("Please contact the author to fix it according to the guidelines.");
+ }
+
+ String prettyVersion = properties.get("prettyVersion");
+ if (prettyVersion == null || prettyVersion.isEmpty())
+ prettyVersion = getPrettyVersion();
+
+ long lastUpdated;
+ try {
+ lastUpdated = Long.parseLong(properties.get("lastUpdated"));
+ }
+ catch (NumberFormatException nfe) {
+ lastUpdated = getLastUpdated();
+ // Better comment these out till all contribs have a lastUpdated
+// System.err.println("The last updated date for the “" + name
+// + "” contribution is not set properly.");
+// System.err
+// .println("Please contact the author to fix it according to the guidelines.");
+ }
+
if (propFile.delete() && propFile.createNewFile() && propFile.setWritable(true)) {
PrintWriter writer = PApplet.createWriter(propFile);
- writer.println("name=" + getName());
- writer.println("category=" + getCategoryStr());
- writer.println("authorList=" + getAuthorList());
- writer.println("url=" + getUrl());
- writer.println("sentence=" + getSentence());
- writer.println("paragraph=" + getParagraph());
- writer.println("version=" + getVersion());
- writer.println("prettyVersion=" + getPrettyVersion());
+ writer.println("name=" + name);
+ writer.println("category=" + category);
+ writer.println("authorList=" + authorList);
+ writer.println("url=" + url);
+ writer.println("sentence=" + sentence);
+ writer.println("paragraph=" + paragraph);
+ writer.println("version=" + version);
+ writer.println("prettyVersion=" + prettyVersion);
+ writer.println("lastUpdated=" + lastUpdated);
writer.flush();
writer.close();
diff --git a/app/src/processing/app/contrib/Contribution.java b/app/src/processing/app/contrib/Contribution.java
index 8367b98d3..9fc73c851 100644
--- a/app/src/processing/app/contrib/Contribution.java
+++ b/app/src/processing/app/contrib/Contribution.java
@@ -43,6 +43,7 @@ abstract public class Contribution {
protected String paragraph; //
protected int version; // 102
protected String prettyVersion; // "1.0.2"
+ protected long lastUpdated; // 1402805757
// "Sound"
@@ -120,6 +121,11 @@ abstract public class Contribution {
public String getPrettyVersion() {
return prettyVersion;
}
+
+ // 1402805757
+ public long getLastUpdated() {
+ return lastUpdated;
+ }
abstract public ContributionType getType();
diff --git a/app/src/processing/app/contrib/ContributionListing.java b/app/src/processing/app/contrib/ContributionListing.java
index 05531f63d..65c16048f 100644
--- a/app/src/processing/app/contrib/ContributionListing.java
+++ b/app/src/processing/app/contrib/ContributionListing.java
@@ -27,6 +27,7 @@ import java.util.*;
import java.util.concurrent.locks.ReentrantLock;
import processing.app.Base;
+import processing.app.Library;
import processing.core.PApplet;
@@ -379,6 +380,19 @@ public class ContributionListing {
}
return false;
}
+
+ boolean hasUpdates(Base base) {
+ for (ModeContribution m : base.getModeContribs())
+ if (hasUpdates(m))
+ return true;
+ for (Library l : base.getActiveEditor().getMode().contribLibraries)
+ if (hasUpdates(l))
+ return true;
+ for (ToolContribution t : base.getActiveEditor().contribTools)
+ if (hasUpdates(t))
+ return true;
+ return false;
+ }
boolean hasUpdates(Contribution contribution) {
@@ -393,6 +407,24 @@ public class ContributionListing {
}
+ String getLatestVersion(Contribution contribution) {
+ Contribution newestContrib = getAvailableContribution(contribution);
+ String latestVersion = newestContrib.getPrettyVersion();
+ if (latestVersion != null && !latestVersion.isEmpty()) {
+ if (latestVersion.toLowerCase().startsWith("build")) // For Python mode
+ return ("v" + latestVersion.substring(5, latestVersion.indexOf(','))
+ .trim());
+ else if (latestVersion.toLowerCase().startsWith("v")) // For ketai library
+ return latestVersion;
+ else
+ return ("v" + latestVersion);
+ }
+ else
+ return null;
+ }
+
+
+
boolean hasDownloadedLatestList() {
return hasDownloadedLatestList;
}
diff --git a/app/src/processing/app/contrib/ContributionManagerDialog.java b/app/src/processing/app/contrib/ContributionManagerDialog.java
index 6583acff9..a4a4e4f70 100644
--- a/app/src/processing/app/contrib/ContributionManagerDialog.java
+++ b/app/src/processing/app/contrib/ContributionManagerDialog.java
@@ -74,6 +74,10 @@ public class ContributionManagerDialog {
}
+ public boolean hasUpdates(Base base) {
+ return contribListing.hasUpdates(base);
+ }
+
public void showFrame(Editor editor) {
this.editor = editor;
@@ -106,7 +110,7 @@ public class ContributionManagerDialog {
status.setErrorMessage("Connection timed out while " +
"downloading the contribution list.");
} else {
- status.setErrorMessage("Could not download the list" +
+ status.setErrorMessage("Could not download the list " +
"of available contributions.");
}
exception.printStackTrace();
@@ -121,6 +125,7 @@ public class ContributionManagerDialog {
* Close the window after an OK or Cancel.
*/
protected void disposeFrame() {
+ status.clear();
dialog.dispose();
editor = null;
}
@@ -163,6 +168,7 @@ public class ContributionManagerDialog {
category = null;
}
filterLibraries(category, filterField.filters);
+ contributionListPanel.updateColors();
}
});
@@ -420,6 +426,8 @@ public class ContributionManagerDialog {
filter = filter.replaceAll("[^\\x30-\\x39^\\x61-\\x7a^\\x3a]", " ");
filters = Arrays.asList(filter.split(" "));
filterLibraries(category, filters);
+
+ contributionListPanel.updateColors();
}
public String getFilterText() {
diff --git a/app/src/processing/app/contrib/ContributionPanel.java b/app/src/processing/app/contrib/ContributionPanel.java
index ca6f2da4e..c4a2763b5 100644
--- a/app/src/processing/app/contrib/ContributionPanel.java
+++ b/app/src/processing/app/contrib/ContributionPanel.java
@@ -28,6 +28,8 @@ import java.net.MalformedURLException;
import java.net.URL;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import java.util.Date;
+import java.text.DateFormat;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
@@ -99,6 +101,7 @@ class ContributionPanel extends JPanel {
installActionListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
+ listPanel.contribManager.status.clear();
if (contrib instanceof AvailableContribution) {
installContribution((AvailableContribution) contrib);
contribListing.replaceContribution(contrib, contrib);
@@ -108,6 +111,7 @@ class ContributionPanel extends JPanel {
undoActionListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
+ listPanel.contribManager.status.clear();
if (contrib instanceof LocalContribution) {
LocalContribution installed = (LocalContribution) contrib;
installed.setDeletionFlag(false);
@@ -118,6 +122,7 @@ class ContributionPanel extends JPanel {
removeActionListener = new ActionListener() {
public void actionPerformed(ActionEvent arg) {
+ listPanel.contribManager.status.clear();
if (contrib.isInstalled() && contrib instanceof LocalContribution) {
updateButton.setEnabled(false);
installRemoveButton.setEnabled(false);
@@ -180,6 +185,9 @@ class ContributionPanel extends JPanel {
descriptionBlock.setContentType("text/html");
setTextStyle(descriptionBlock);
descriptionBlock.setOpaque(false);
+ if (UIManager.getLookAndFeel().getID().equals("Nimbus")) {
+ descriptionBlock.setBackground(new Color(0, 0, 0, 0));
+ }
// stripTextSelectionListeners(descriptionBlock);
descriptionBlock.setBorder(new EmptyBorder(4, 7, 7, 7));
@@ -209,6 +217,7 @@ class ContributionPanel extends JPanel {
updateButton.setVisible(false);
updateButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
+ listPanel.contribManager.status.clear();
updateButton.setEnabled(false);
AvailableContribution ad = contribListing.getAvailableContribution(contrib);
String url = ad.link;
@@ -359,6 +368,29 @@ class ContributionPanel extends JPanel {
}
description.append(sentence);
}
+
+ String version = contrib.getPrettyVersion();
+
+ if (version != null && !version.isEmpty()) {
+ description.append("
");
+ if (version.toLowerCase().startsWith("build")) // For Python mode
+ description.append("v"
+ + version.substring(5, version.indexOf(',')).trim());
+ else if (version.toLowerCase().startsWith("v")) // For ketai library
+ description.append(version);
+ else
+ description.append("v" + version);
+ }
+
+ long lastUpdatedUTC = contrib.getLastUpdated();
+ if (lastUpdatedUTC != 0) {
+ DateFormat dateFormatter = DateFormat.getDateInstance(DateFormat.MEDIUM);
+ Date lastUpdatedDate = new Date(lastUpdatedUTC);
+ if (version != null && !version.isEmpty())
+ description.append(", ");
+ description.append("Last Updated on " + dateFormatter.format(lastUpdatedDate));
+ }
+
description.append("