diff --git a/.classpath b/.classpath
new file mode 100644
index 000000000..71e8cc144
--- /dev/null
+++ b/.classpath
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/.project b/.project
new file mode 100644
index 000000000..0b76a40ba
--- /dev/null
+++ b/.project
@@ -0,0 +1,17 @@
+
+
+ processing-head
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 000000000..ef277e5a2
--- /dev/null
+++ b/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,263 @@
+#Thu Jan 10 10:50:38 PST 2008
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.2
+org.eclipse.jdt.core.compiler.compliance=1.4
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=warning
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=warning
+org.eclipse.jdt.core.compiler.source=1.3
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
+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=16
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+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.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=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
+org.eclipse.jdt.core.formatter.comment.format_block_comments=true
+org.eclipse.jdt.core.formatter.comment.format_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=true
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
+org.eclipse.jdt.core.formatter.comment.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.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+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_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_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_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_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_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_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.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=false
+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_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
diff --git a/.settings/org.eclipse.jdt.ui.prefs b/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 000000000..677b9819b
--- /dev/null
+++ b/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,4 @@
+#Thu Jan 10 10:50:38 PST 2008
+eclipse.preferences.version=1
+formatter_settings_version=11
+org.eclipse.jdt.ui.text.custom_code_templates=
diff --git a/app/.classpath b/app/.classpath
new file mode 100644
index 000000000..26775c499
--- /dev/null
+++ b/app/.classpath
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/.classpath_macosx b/app/.classpath_macosx
new file mode 100644
index 000000000..26775c499
--- /dev/null
+++ b/app/.classpath_macosx
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/.classpath_vista b/app/.classpath_vista
new file mode 100755
index 000000000..c7ec5acb9
--- /dev/null
+++ b/app/.classpath_vista
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/.project b/app/.project
new file mode 100644
index 000000000..69a82c3d0
--- /dev/null
+++ b/app/.project
@@ -0,0 +1,17 @@
+
+
+ processing
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/app/.settings/org.eclipse.jdt.core.prefs b/app/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 000000000..d6676cc6b
--- /dev/null
+++ b/app/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,320 @@
+#Wed Jun 04 15:47:46 EDT 2008
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.5
+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.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.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.incompatibleNonInheritedInterfaceMethod=warning
+org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore
+org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
+org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
+org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
+org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=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.nullReference=ignore
+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.rawTypeReference=ignore
+org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
+org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
+org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
+org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
+org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
+org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
+org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=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=ignore
+org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore
+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.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.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.source=1.5
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+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=18
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=82
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+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_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.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=true
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
+org.eclipse.jdt.core.formatter.comment.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.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+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_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_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_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_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_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_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.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=false
+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_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
diff --git a/app/.settings/org.eclipse.jdt.ui.prefs b/app/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 000000000..4ce979da4
--- /dev/null
+++ b/app/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,4 @@
+#Tue Jun 03 17:00:03 EDT 2008
+eclipse.preferences.version=1
+formatter_profile=_two spaces no tabs
+formatter_settings_version=11
diff --git a/app/lib/antlr.jar b/app/lib/antlr.jar
new file mode 100644
index 000000000..42f25e540
Binary files /dev/null and b/app/lib/antlr.jar differ
diff --git a/app/lib/apple.jar b/app/lib/apple.jar
new file mode 100755
index 000000000..160d62b66
Binary files /dev/null and b/app/lib/apple.jar differ
diff --git a/app/lib/ecj.jar b/app/lib/ecj.jar
new file mode 100644
index 000000000..878a32cfc
Binary files /dev/null and b/app/lib/ecj.jar differ
diff --git a/app/lib/jna.jar b/app/lib/jna.jar
new file mode 100644
index 000000000..5c669aff6
Binary files /dev/null and b/app/lib/jna.jar differ
diff --git a/app/src/antlr/ExtendedCommonASTWithHiddenTokens.java b/app/src/antlr/ExtendedCommonASTWithHiddenTokens.java
new file mode 100644
index 000000000..d997f0be8
--- /dev/null
+++ b/app/src/antlr/ExtendedCommonASTWithHiddenTokens.java
@@ -0,0 +1,132 @@
+package antlr;
+
+/* ANTLR Translator Generator
+ * Project led by Terence Parr at http://www.jGuru.com
+ * Software rights: http://www.antlr.org/RIGHTS.html
+ *
+ * $Id: ExtendedCommonASTWithHiddenTokens.java 3419 2007-07-16 14:02:05Z fry $
+ */
+
+import java.io.*;
+//import antlr.*;
+import antlr.collections.*;
+//import antlr.collections.impl.*;
+
+/** A CommonAST whose initialization copies hidden token
+ * information from the Token used to create a node.
+ */
+public class ExtendedCommonASTWithHiddenTokens
+ extends CommonASTWithHiddenTokens {
+
+ public ExtendedCommonASTWithHiddenTokens() {
+ super();
+ }
+
+ public ExtendedCommonASTWithHiddenTokens(Token tok) {
+ super(tok);
+ }
+
+ public void initialize(AST ast) {
+ ExtendedCommonASTWithHiddenTokens a =
+ (ExtendedCommonASTWithHiddenTokens)ast;
+ super.initialize(a);
+ hiddenBefore = a.getHiddenBefore();
+ hiddenAfter = a.getHiddenAfter();
+ }
+
+ public String getHiddenAfterString() {
+
+ CommonHiddenStreamToken t;
+ StringBuffer hiddenAfterString = new StringBuffer(100);
+
+ for ( t = hiddenAfter ; t != null ; t = t.getHiddenAfter() ) {
+ hiddenAfterString.append(t.getText());
+ }
+
+ return hiddenAfterString.toString();
+ }
+
+ public String getHiddenBeforeString() {
+
+ antlr.CommonHiddenStreamToken
+ child = null,
+ parent = hiddenBefore;
+
+ // if there aren't any hidden tokens here, quietly return
+ //
+ if (parent == null) {
+ return "";
+ }
+
+ // traverse back to the head of the list of tokens before this node
+ do {
+ child = parent;
+ parent = child.getHiddenBefore();
+ } while (parent != null);
+
+ // dump that list
+
+ StringBuffer hiddenBeforeString = new StringBuffer(100);
+
+ for ( CommonHiddenStreamToken t = child; t != null ;
+ t = t.getHiddenAfter() ) {
+ hiddenBeforeString.append(t.getText());
+ }
+
+ return hiddenBeforeString.toString();
+ }
+
+ public void xmlSerializeNode(Writer out)
+ throws IOException {
+ StringBuffer buf = new StringBuffer(100);
+ buf.append("<");
+ buf.append(getClass().getName() + " ");
+
+ buf.append("hiddenBeforeString=\"" +
+ encode(getHiddenBeforeString()) +
+ "\" text=\"" + encode(getText()) + "\" type=\"" +
+ getType() + "\" hiddenAfterString=\"" +
+ encode(getHiddenAfterString()) + "\"/>");
+ out.write(buf.toString());
+ }
+
+ public void xmlSerializeRootOpen(Writer out)
+ throws IOException {
+ StringBuffer buf = new StringBuffer(100);
+ buf.append("<");
+ buf.append(getClass().getName() + " ");
+ buf.append("hiddenBeforeString=\"" +
+ encode(getHiddenBeforeString()) +
+ "\" text=\"" + encode(getText()) + "\" type=\"" +
+ getType() + "\" hiddenAfterString=\"" +
+ encode(getHiddenAfterString()) + "\">\n");
+ out.write(buf.toString());
+ }
+
+ public void xmlSerializeRootClose(Writer out)
+ throws IOException {
+ out.write("" + getClass().getName() + ">\n");
+ }
+
+ public void xmlSerialize(Writer out) throws IOException {
+ // print out this node and all siblings
+ for (AST node = this;
+ node != null;
+ node = node.getNextSibling()) {
+ if (node.getFirstChild() == null) {
+ // print guts (class name, attributes)
+ ((BaseAST)node).xmlSerializeNode(out);
+ }
+ else {
+ ((BaseAST)node).xmlSerializeRootOpen(out);
+
+ // print children
+ ((BaseAST)node.getFirstChild()).xmlSerialize(out);
+
+ // print end tag
+ ((BaseAST)node).xmlSerializeRootClose(out);
+ }
+ }
+ }
+
+}
diff --git a/app/src/antlr/TokenStreamCopyingHiddenTokenFilter.java b/app/src/antlr/TokenStreamCopyingHiddenTokenFilter.java
new file mode 100644
index 000000000..cd3306aed
--- /dev/null
+++ b/app/src/antlr/TokenStreamCopyingHiddenTokenFilter.java
@@ -0,0 +1,221 @@
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+package antlr;
+//package processing.app.preproc;
+
+
+//import antlr.*;
+import antlr.collections.impl.BitSet;
+
+/**
+ * This class provides TokenStreamHiddenTokenFilters with the concept of
+ * tokens which can be copied so that they are seen by both the hidden token
+ * stream as well as the parser itself. This is useful when one wants to use
+ * an existing parser (like the Java parser included with ANTLR) that throws
+ * away some tokens to create a parse tree which can be used to spit out
+ * a copy of the code with only minor modifications.
+ *
+ * This code is partially derived from the public domain ANLTR TokenStream
+ */
+public class TokenStreamCopyingHiddenTokenFilter
+ extends TokenStreamHiddenTokenFilter
+ implements TokenStream {
+
+ protected BitSet copyMask;
+ CommonHiddenStreamToken hiddenCopy = null;
+
+ public TokenStreamCopyingHiddenTokenFilter(TokenStream input) {
+ super(input);
+ copyMask = new BitSet();
+ }
+
+ /**
+ * Indicate that all tokens of type tokenType should be copied. The copy
+ * is put in the stream of hidden tokens, and the original is returned in the
+ * stream of normal tokens.
+ *
+ * @param tokenType integer representing the token type to copied
+ */
+ public void copy(int tokenType) {
+ copyMask.add(tokenType);
+ }
+
+ /**
+ * Create a clone of the important parts of the given token. Note that this
+ * does NOT copy the hiddenBefore and hiddenAfter fields.
+ *
+ * @param t token to partially clone
+ * @return newly created partial clone
+ */
+ public CommonHiddenStreamToken partialCloneToken(CommonHiddenStreamToken t) {
+
+ CommonHiddenStreamToken u = new CommonHiddenStreamToken(t.getType(),
+ t.getText());
+ u.setColumn(t.getColumn());
+ u.setLine(t.getLine());
+ u.setFilename(t.getFilename());
+
+ return u;
+ }
+
+ public void linkAndCopyToken(CommonHiddenStreamToken prev,
+ CommonHiddenStreamToken monitored) {
+ // create a copy of the token in the lookahead for use as hidden token
+ hiddenCopy = partialCloneToken(LA(1));
+
+ // attach copy to the previous token, whether hidden or monitored
+ prev.setHiddenAfter(hiddenCopy);
+
+ // if previous token was hidden, set the hiddenBefore pointer of the
+ // copy to point back to it
+ if (prev != monitored) {
+ hiddenCopy.setHiddenBefore(prev);
+ }
+
+ // we don't want the non-hidden copy to link back to the hidden
+ // copy on the next pass through this function, so we leave
+ // lastHiddenToken alone
+
+ //System.err.println("hidden copy: " + hiddenCopy.toString());
+
+ return;
+ }
+
+ private void consumeFirst() throws TokenStreamException {
+ consume(); // get first token of input stream
+
+ // Handle situation where hidden or discarded tokens
+ // appear first in input stream
+ CommonHiddenStreamToken p=null;
+
+ // while hidden, copied, or discarded scarf tokens
+ while ( hideMask.member(LA(1).getType()) ||
+ discardMask.member(LA(1).getType()) ||
+ copyMask.member(LA(1).getType()) ) {
+
+ // if we've hit one of the tokens that needs to be copied, we copy it
+ // and then break out of the loop, because the parser needs to see it
+ // too
+ //
+ if (copyMask.member(LA(1).getType())) {
+
+ // copy the token in the lookahead
+ hiddenCopy = partialCloneToken(LA(1));
+
+ // if there's an existing token before this, link that and the
+ // copy together
+ if (p != null) {
+ p.setHiddenAfter(hiddenCopy);
+ hiddenCopy.setHiddenBefore(p); // double-link
+ }
+
+ lastHiddenToken = hiddenCopy;
+ if (firstHidden == null) {
+ firstHidden = hiddenCopy;
+ }
+
+ // we don't want to consume this token, because it also needs to
+ // be passed through to the parser, so break out of the while look
+ // entirely
+ //
+ break;
+ } else if (hideMask.member(LA(1).getType())) {
+ if (p != null) {
+ p.setHiddenAfter(LA(1));
+ LA(1).setHiddenBefore(p); // double-link
+ }
+ p = LA(1);
+
+ lastHiddenToken = p;
+ if (firstHidden == null) {
+ firstHidden = p; // record hidden token if first
+ }
+ }
+ consume();
+ }
+ }
+
+ /** Return the next monitored token.
+ * Test the token following the monitored token.
+ * If following is another monitored token, save it
+ * for the next invocation of nextToken (like a single
+ * lookahead token) and return it then.
+ * If following is unmonitored, nondiscarded (hidden)
+ * channel token, add it to the monitored token.
+ *
+ * Note: EOF must be a monitored Token.
+ */
+ public Token nextToken() throws TokenStreamException {
+ // handle an initial condition; don't want to get lookahead
+ // token of this splitter until first call to nextToken
+ if (LA(1) == null) {
+ consumeFirst();
+ }
+
+ //System.err.println();
+
+ // we always consume hidden tokens after monitored, thus,
+ // upon entry LA(1) is a monitored token.
+ CommonHiddenStreamToken monitored = LA(1);
+
+ // point to hidden tokens found during last invocation
+ monitored.setHiddenBefore(lastHiddenToken);
+ lastHiddenToken = null;
+
+ // Look for hidden tokens, hook them into list emanating
+ // from the monitored tokens.
+ consume();
+ CommonHiddenStreamToken prev = monitored;
+
+ // deal with as many not-purely-monitored tokens as possible
+ while ( hideMask.member(LA(1).getType()) ||
+ discardMask.member(LA(1).getType()) ||
+ copyMask.member(LA(1).getType()) ) {
+
+ if (copyMask.member(LA(1).getType())) {
+
+ // copy the token and link it backwards
+ if (hiddenCopy != null) {
+ linkAndCopyToken(hiddenCopy, monitored);
+ } else {
+ linkAndCopyToken(prev, monitored);
+ }
+
+ // we now need to parse it as a monitored token, so we return, which
+ // avoids the consume() call at the end of this loop. the next call
+ // will parse it as a monitored token.
+ //System.err.println("returned: " + monitored.toString());
+ return monitored;
+
+ } else if (hideMask.member(LA(1).getType())) {
+
+ // attach the hidden token to the monitored in a chain
+ // link forwards
+ prev.setHiddenAfter(LA(1));
+
+ // link backwards
+ if (prev != monitored) { //hidden cannot point to monitored tokens
+ LA(1).setHiddenBefore(prev);
+ } else if (hiddenCopy != null) {
+ hiddenCopy.setHiddenAfter(LA(1));
+ LA(1).setHiddenBefore(hiddenCopy);
+ hiddenCopy = null;
+ }
+
+ //System.err.println("hidden: " + prev.getHiddenAfter().toString() + "\" after: " + prev.toString());
+ prev = lastHiddenToken = LA(1);
+ }
+
+ consume();
+ }
+
+ // remember the last hidden token for next time around
+ if (hiddenCopy != null) {
+ lastHiddenToken = hiddenCopy;
+ hiddenCopy = null;
+ }
+
+ //System.err.println("returned: " + monitored.toString());
+ return monitored;
+ }
+}
diff --git a/app/src/antlr/java/java.g b/app/src/antlr/java/java.g
new file mode 100644
index 000000000..ee948ccd0
--- /dev/null
+++ b/app/src/antlr/java/java.g
@@ -0,0 +1,1277 @@
+header {
+package antlr.java;
+}
+
+/** Java 1.3 Recognizer
+ *
+ * Run 'java Main [-showtree] directory-full-of-java-files'
+ *
+ * [The -showtree option pops up a Swing frame that shows
+ * the AST constructed from the parser.]
+ *
+ * Run 'java Main '
+ *
+ * Contributing authors:
+ * John Mitchell johnm@non.net
+ * Terence Parr parrt@magelang.com
+ * John Lilley jlilley@empathy.com
+ * Scott Stanchfield thetick@magelang.com
+ * Markus Mohnen mohnen@informatik.rwth-aachen.de
+ * Peter Williams pete.williams@sun.com
+ * Allan Jacobs Allan.Jacobs@eng.sun.com
+ * Steve Messick messick@redhills.com
+ * John Pybus john@pybus.org
+ *
+ * Version 1.00 December 9, 1997 -- initial release
+ * Version 1.01 December 10, 1997
+ * fixed bug in octal def (0..7 not 0..8)
+ * Version 1.10 August 1998 (parrt)
+ * added tree construction
+ * fixed definition of WS,comments for mac,pc,unix newlines
+ * added unary plus
+ * Version 1.11 (Nov 20, 1998)
+ * Added "shutup" option to turn off last ambig warning.
+ * Fixed inner class def to allow named class defs as statements
+ * synchronized requires compound not simple statement
+ * add [] after builtInType DOT class in primaryExpression
+ * "const" is reserved but not valid..removed from modifiers
+ * Version 1.12 (Feb 2, 1999)
+ * Changed LITERAL_xxx to xxx in tree grammar.
+ * Updated java.g to use tokens {...} now for 2.6.0 (new feature).
+ *
+ * Version 1.13 (Apr 23, 1999)
+ * Didn't have (stat)? for else clause in tree parser.
+ * Didn't gen ASTs for interface extends. Updated tree parser too.
+ * Updated to 2.6.0.
+ * Version 1.14 (Jun 20, 1999)
+ * Allowed final/abstract on local classes.
+ * Removed local interfaces from methods
+ * Put instanceof precedence where it belongs...in relationalExpr
+ * It also had expr not type as arg; fixed it.
+ * Missing ! on SEMI in classBlock
+ * fixed: (expr) + "string" was parsed incorrectly (+ as unary plus).
+ * fixed: didn't like Object[].class in parser or tree parser
+ * Version 1.15 (Jun 26, 1999)
+ * Screwed up rule with instanceof in it. :( Fixed.
+ * Tree parser didn't like (expr).something; fixed.
+ * Allowed multiple inheritance in tree grammar. oops.
+ * Version 1.16 (August 22, 1999)
+ * Extending an interface built a wacky tree: had extra EXTENDS.
+ * Tree grammar didn't allow multiple superinterfaces.
+ * Tree grammar didn't allow empty var initializer: {}
+ * Version 1.17 (October 12, 1999)
+ * ESC lexer rule allowed 399 max not 377 max.
+ * java.tree.g didn't handle the expression of synchronized
+ * statements.
+ * Version 1.18 (August 12, 2001)
+ * Terence updated to Java 2 Version 1.3 by
+ * observing/combining work of Allan Jacobs and Steve
+ * Messick. Handles 1.3 src. Summary:
+ * o primary didn't include boolean.class kind of thing
+ * o constructor calls parsed explicitly now:
+ * see explicitConstructorInvocation
+ * o add strictfp modifier
+ * o missing objBlock after new expression in tree grammar
+ * o merged local class definition alternatives, moved after declaration
+ * o fixed problem with ClassName.super.field
+ * o reordered some alternatives to make things more efficient
+ * o long and double constants were not differentiated from int/float
+ * o whitespace rule was inefficient: matched only one char
+ * o add an examples directory with some nasty 1.3 cases
+ * o made Main.java use buffered IO and a Reader for Unicode support
+ * o supports UNICODE?
+ * Using Unicode charVocabulay makes code file big, but only
+ * in the bitsets at the end. I need to make ANTLR generate
+ * unicode bitsets more efficiently.
+ * Version 1.19 (April 25, 2002)
+ * Terence added in nice fixes by John Pybus concerning floating
+ * constants and problems with super() calls. John did a nice
+ * reorg of the primary/postfix expression stuff to read better
+ * and makes f.g.super() parse properly (it was METHOD_CALL not
+ * a SUPER_CTOR_CALL). Also:
+ *
+ * o "finally" clause was a root...made it a child of "try"
+ * o Added stuff for asserts too for Java 1.4, but *commented out*
+ * as it is not backward compatible.
+ *
+ * Version 1.20 (October 27, 2002)
+ *
+ * Terence ended up reorging John Pybus' stuff to
+ * remove some nondeterminisms and some syntactic predicates.
+ * Note that the grammar is stricter now; e.g., this(...) must
+ * be the first statement.
+ *
+ * Trinary ?: operator wasn't working as array name:
+ * (isBig ? bigDigits : digits)[i];
+ *
+ * Checked parser/tree parser on source for
+ * Resin-2.0.5, jive-2.1.1, jdk 1.3.1, Lucene, antlr 2.7.2a4,
+ * and the 110k-line jGuru server source.
+ *
+ * This grammar is in the PUBLIC DOMAIN
+ *
+ */
+class JavaRecognizer extends Parser;
+options {
+ k = 2; // two token lookahead
+ exportVocab=Java; // Call its vocabulary "Java"
+ codeGenMakeSwitchThreshold = 2; // Some optimizations
+ codeGenBitsetTestThreshold = 3;
+ defaultErrorHandler = false; // Don't generate parser error handlers
+ buildAST = true;
+}
+
+tokens {
+ BLOCK; MODIFIERS; OBJBLOCK; SLIST; CTOR_DEF; METHOD_DEF; VARIABLE_DEF;
+ INSTANCE_INIT; STATIC_INIT; TYPE; CLASS_DEF; INTERFACE_DEF;
+ PACKAGE_DEF; ARRAY_DECLARATOR; EXTENDS_CLAUSE; IMPLEMENTS_CLAUSE;
+ PARAMETERS; PARAMETER_DEF; LABELED_STAT; TYPECAST; INDEX_OP;
+ POST_INC; POST_DEC; METHOD_CALL; EXPR; ARRAY_INIT;
+ IMPORT; UNARY_MINUS; UNARY_PLUS; CASE_GROUP; ELIST; FOR_INIT; FOR_CONDITION;
+ FOR_ITERATOR; EMPTY_STAT; FINAL="final"; ABSTRACT="abstract";
+ STRICTFP="strictfp"; SUPER_CTOR_CALL; CTOR_CALL;
+}
+
+// Compilation Unit: In Java, this is a single file. This is the start
+// rule for this parser
+compilationUnit
+ : // A compilation unit starts with an optional package definition
+ ( packageDefinition
+ | /* nothing */
+ )
+
+ // Next we have a series of zero or more import statements
+ ( importDefinition )*
+
+ // Wrapping things up with any number of class or interface
+ // definitions
+ ( typeDefinition )*
+
+ EOF!
+ ;
+
+
+// Package statement: "package" followed by an identifier.
+packageDefinition
+ options {defaultErrorHandler = true;} // let ANTLR handle errors
+ : p:"package"^ {#p.setType(PACKAGE_DEF);} identifier SEMI!
+ ;
+
+
+// Import statement: import followed by a package or class name
+importDefinition
+ options {defaultErrorHandler = true;}
+ : i:"import"^ {#i.setType(IMPORT);} identifierStar SEMI!
+ ;
+
+// A type definition in a file is either a class or interface definition.
+typeDefinition
+ options {defaultErrorHandler = true;}
+ : m:modifiers!
+ ( classDefinition[#m]
+ | interfaceDefinition[#m]
+ )
+ | SEMI!
+ ;
+
+/** A declaration is the creation of a reference or primitive-type variable
+ * Create a separate Type/Var tree for each var in the var list.
+ */
+declaration!
+ : m:modifiers t:typeSpec[false] v:variableDefinitions[#m,#t]
+ {#declaration = #v;}
+ ;
+
+// A type specification is a type name with possible brackets afterwards
+// (which would make it an array type).
+typeSpec[boolean addImagNode]
+ : classTypeSpec[addImagNode]
+ | builtInTypeSpec[addImagNode]
+ ;
+
+// A class type specification is a class type with possible brackets afterwards
+// (which would make it an array type).
+classTypeSpec[boolean addImagNode]
+ : identifier (lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK!)*
+ {
+ if ( addImagNode ) {
+ #classTypeSpec = #(#[TYPE,"TYPE"], #classTypeSpec);
+ }
+ }
+ ;
+
+// A builtin type specification is a builtin type with possible brackets
+// afterwards (which would make it an array type).
+builtInTypeSpec[boolean addImagNode]
+ : builtInType (lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK!)*
+ {
+ if ( addImagNode ) {
+ #builtInTypeSpec = #(#[TYPE,"TYPE"], #builtInTypeSpec);
+ }
+ }
+ ;
+
+// A type name. which is either a (possibly qualified) class name or
+// a primitive (builtin) type
+type
+ : identifier
+ | builtInType
+ ;
+
+// The primitive types.
+builtInType
+ : "void"
+ | "boolean"
+ | "byte"
+ | "char"
+ | "short"
+ | "int"
+ | "float"
+ | "long"
+ | "double"
+ ;
+
+// A (possibly-qualified) java identifier. We start with the first IDENT
+// and expand its name by adding dots and following IDENTS
+identifier
+ : IDENT ( DOT^ IDENT )*
+ ;
+
+identifierStar
+ : IDENT
+ ( DOT^ IDENT )*
+ ( DOT^ STAR )?
+ ;
+
+// A list of zero or more modifiers. We could have used (modifier)* in
+// place of a call to modifiers, but I thought it was a good idea to keep
+// this rule separate so they can easily be collected in a Vector if
+// someone so desires
+modifiers
+ : ( modifier )*
+ {#modifiers = #([MODIFIERS, "MODIFIERS"], #modifiers);}
+ ;
+
+// modifiers for Java classes, interfaces, class/instance vars and methods
+modifier
+ : "private"
+ | "public"
+ | "protected"
+ | "static"
+ | "transient"
+ | "final"
+ | "abstract"
+ | "native"
+ | "threadsafe"
+ | "synchronized"
+// | "const" // reserved word, but not valid
+ | "volatile"
+ | "strictfp"
+ ;
+
+// Definition of a Java class
+classDefinition![AST modifiers]
+ : "class" IDENT
+ // it _might_ have a superclass...
+ sc:superClassClause
+ // it might implement some interfaces...
+ ic:implementsClause
+ // now parse the body of the class
+ cb:classBlock
+ {#classDefinition = #(#[CLASS_DEF,"CLASS_DEF"],
+ modifiers,IDENT,sc,ic,cb);}
+ ;
+
+superClassClause!
+ : ( "extends" id:identifier )?
+ {#superClassClause = #(#[EXTENDS_CLAUSE,"EXTENDS_CLAUSE"],id);}
+ ;
+
+// Definition of a Java Interface
+interfaceDefinition![AST modifiers]
+ : "interface" IDENT
+ // it might extend some other interfaces
+ ie:interfaceExtends
+ // now parse the body of the interface (looks like a class...)
+ cb:classBlock
+ {#interfaceDefinition = #(#[INTERFACE_DEF,"INTERFACE_DEF"],
+ modifiers,IDENT,ie,cb);}
+ ;
+
+
+// This is the body of a class. You can have fields and extra semicolons,
+// That's about it (until you see what a field is...)
+classBlock
+ : LCURLY!
+ ( field | SEMI! )*
+ RCURLY!
+ {#classBlock = #([OBJBLOCK, "OBJBLOCK"], #classBlock);}
+ ;
+
+// An interface can extend several other interfaces...
+interfaceExtends
+ : (
+ e:"extends"!
+ identifier ( COMMA! identifier )*
+ )?
+ {#interfaceExtends = #(#[EXTENDS_CLAUSE,"EXTENDS_CLAUSE"],
+ #interfaceExtends);}
+ ;
+
+// A class can implement several interfaces...
+implementsClause
+ : (
+ i:"implements"! identifier ( COMMA! identifier )*
+ )?
+ {#implementsClause = #(#[IMPLEMENTS_CLAUSE,"IMPLEMENTS_CLAUSE"],
+ #implementsClause);}
+ ;
+
+// Now the various things that can be defined inside a class or interface...
+// Note that not all of these are really valid in an interface (constructors,
+// for example), and if this grammar were used for a compiler there would
+// need to be some semantic checks to make sure we're doing the right thing...
+field!
+ : // method, constructor, or variable declaration
+ mods:modifiers
+ ( h:ctorHead s:constructorBody // constructor
+ {#field = #(#[CTOR_DEF,"CTOR_DEF"], mods, h, s);}
+
+ | cd:classDefinition[#mods] // inner class
+ {#field = #cd;}
+
+ | id:interfaceDefinition[#mods] // inner interface
+ {#field = #id;}
+
+ | t:typeSpec[false] // method or variable declaration(s)
+ ( IDENT // the name of the method
+
+ // parse the formal parameter declarations.
+ LPAREN! param:parameterDeclarationList RPAREN!
+
+ rt:declaratorBrackets[#t]
+
+ // get the list of exceptions that this method is
+ // declared to throw
+ (tc:throwsClause)?
+
+ ( s2:compoundStatement | SEMI )
+ {#field = #(#[METHOD_DEF,"METHOD_DEF"],
+ mods,
+ #(#[TYPE,"TYPE"],rt),
+ IDENT,
+ param,
+ tc,
+ s2);}
+ | v:variableDefinitions[#mods,#t] SEMI
+// {#field = #(#[VARIABLE_DEF,"VARIABLE_DEF"], v);}
+ {#field = #v;}
+ )
+ )
+
+ // "static { ... }" class initializer
+ | "static" s3:compoundStatement
+ {#field = #(#[STATIC_INIT,"STATIC_INIT"], s3);}
+
+ // "{ ... }" instance initializer
+ | s4:compoundStatement
+ {#field = #(#[INSTANCE_INIT,"INSTANCE_INIT"], s4);}
+ ;
+
+constructorBody
+ : lc:LCURLY^ {#lc.setType(SLIST);}
+ ( options { greedy=true; } : explicitConstructorInvocation)?
+ (statement)*
+ RCURLY!
+ ;
+
+/** Catch obvious constructor calls, but not the expr.super(...) calls */
+explicitConstructorInvocation
+ : "this"! lp1:LPAREN^ argList RPAREN! SEMI!
+ {#lp1.setType(CTOR_CALL);}
+ | "super"! lp2:LPAREN^ argList RPAREN! SEMI!
+ {#lp2.setType(SUPER_CTOR_CALL);}
+ ;
+
+variableDefinitions[AST mods, AST t]
+ : variableDeclarator[getASTFactory().dupTree(mods),
+ getASTFactory().dupTree(t)]
+ ( COMMA!
+ variableDeclarator[getASTFactory().dupTree(mods),
+ getASTFactory().dupTree(t)]
+ )*
+ ;
+
+/** Declaration of a variable. This can be a class/instance variable,
+ * or a local variable in a method
+ * It can also include possible initialization.
+ */
+variableDeclarator![AST mods, AST t]
+ : id:IDENT d:declaratorBrackets[t] v:varInitializer
+ {#variableDeclarator = #(#[VARIABLE_DEF,"VARIABLE_DEF"], mods, #(#[TYPE,"TYPE"],d), id, v);}
+ ;
+
+declaratorBrackets[AST typ]
+ : {#declaratorBrackets=typ;}
+ (lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK!)*
+ ;
+
+varInitializer
+ : ( ASSIGN^ initializer )?
+ ;
+
+// This is an initializer used to set up an array.
+arrayInitializer
+ : lc:LCURLY^ {#lc.setType(ARRAY_INIT);}
+ ( initializer
+ (
+ // CONFLICT: does a COMMA after an initializer start a new
+ // initializer or start the option ',' at end?
+ // ANTLR generates proper code by matching
+ // the comma as soon as possible.
+ options {
+ warnWhenFollowAmbig = false;
+ }
+ :
+ COMMA! initializer
+ )*
+ (COMMA!)?
+ )?
+ RCURLY!
+ ;
+
+
+// The two "things" that can initialize an array element are an expression
+// and another (nested) array initializer.
+initializer
+ : expression
+ | arrayInitializer
+ ;
+
+// This is the header of a method. It includes the name and parameters
+// for the method.
+// This also watches for a list of exception classes in a "throws" clause.
+ctorHead
+ : IDENT // the name of the method
+
+ // parse the formal parameter declarations.
+ LPAREN! parameterDeclarationList RPAREN!
+
+ // get the list of exceptions that this method is declared to throw
+ (throwsClause)?
+ ;
+
+// This is a list of exception classes that the method is declared to throw
+throwsClause
+ : "throws"^ identifier ( COMMA! identifier )*
+ ;
+
+
+// A list of formal parameters
+parameterDeclarationList
+ : ( parameterDeclaration ( COMMA! parameterDeclaration )* )?
+ {#parameterDeclarationList = #(#[PARAMETERS,"PARAMETERS"],
+ #parameterDeclarationList);}
+ ;
+
+// A formal parameter.
+parameterDeclaration!
+ : pm:parameterModifier t:typeSpec[false] id:IDENT
+ pd:declaratorBrackets[#t]
+ {#parameterDeclaration = #(#[PARAMETER_DEF,"PARAMETER_DEF"],
+ pm, #([TYPE,"TYPE"],pd), id);}
+ ;
+
+parameterModifier
+ : (f:"final")?
+ {#parameterModifier = #(#[MODIFIERS,"MODIFIERS"], f);}
+ ;
+
+// Compound statement. This is used in many contexts:
+// Inside a class definition prefixed with "static":
+// it is a class initializer
+// Inside a class definition without "static":
+// it is an instance initializer
+// As the body of a method
+// As a completely indepdent braced block of code inside a method
+// it starts a new scope for variable definitions
+
+compoundStatement
+ : lc:LCURLY^ {#lc.setType(SLIST);}
+ // include the (possibly-empty) list of statements
+ (statement)*
+ RCURLY!
+ ;
+
+
+statement
+ // A list of statements in curly braces -- start a new scope!
+ : compoundStatement
+
+ // declarations are ambiguous with "ID DOT" relative to expression
+ // statements. Must backtrack to be sure. Could use a semantic
+ // predicate to test symbol table to see what the type was coming
+ // up, but that's pretty hard without a symbol table ;)
+ | (declaration)=> declaration SEMI!
+
+ // An expression statement. This could be a method call,
+ // assignment statement, or any other expression evaluated for
+ // side-effects.
+ | expression SEMI!
+
+ // class definition
+ | m:modifiers! classDefinition[#m]
+
+ // Attach a label to the front of a statement
+ | IDENT c:COLON^ {#c.setType(LABELED_STAT);} statement
+
+ // If-else statement
+ | "if"^ LPAREN! expression RPAREN! statement
+ (
+ // CONFLICT: the old "dangling-else" problem...
+ // ANTLR generates proper code matching
+ // as soon as possible. Hush warning.
+ options {
+ warnWhenFollowAmbig = false;
+ }
+ :
+ "else"! statement
+ )?
+
+ // For statement
+ | "for"^
+ LPAREN!
+ forInit SEMI! // initializer
+ forCond SEMI! // condition test
+ forIter // updater
+ RPAREN!
+ statement // statement to loop over
+
+ // While statement
+ | "while"^ LPAREN! expression RPAREN! statement
+
+ // do-while statement
+ | "do"^ statement "while"! LPAREN! expression RPAREN! SEMI!
+
+ // get out of a loop (or switch)
+ | "break"^ (IDENT)? SEMI!
+
+ // do next iteration of a loop
+ | "continue"^ (IDENT)? SEMI!
+
+ // Return an expression
+ | "return"^ (expression)? SEMI!
+
+ // switch/case statement
+ | "switch"^ LPAREN! expression RPAREN! LCURLY!
+ ( casesGroup )*
+ RCURLY!
+
+ // exception try-catch block
+ | tryBlock
+
+ // throw an exception
+ | "throw"^ expression SEMI!
+
+ // synchronize a statement
+ | "synchronized"^ LPAREN! expression RPAREN! compoundStatement
+
+ // asserts (uncomment if you want 1.4 compatibility)
+ | "assert"^ expression ( COLON! expression )? SEMI!
+
+ // empty statement
+ | s:SEMI {#s.setType(EMPTY_STAT);}
+ ;
+
+casesGroup
+ : ( // CONFLICT: to which case group do the statements bind?
+ // ANTLR generates proper code: it groups the
+ // many "case"/"default" labels together then
+ // follows them with the statements
+ options {
+ greedy = true;
+ }
+ :
+ aCase
+ )+
+ caseSList
+ {#casesGroup = #([CASE_GROUP, "CASE_GROUP"], #casesGroup);}
+ ;
+
+aCase
+ : ("case"^ expression | "default") COLON!
+ ;
+
+caseSList
+ : (statement)*
+ {#caseSList = #(#[SLIST,"SLIST"],#caseSList);}
+ ;
+
+// The initializer for a for loop
+forInit
+ // if it looks like a declaration, it is
+ : ( (declaration)=> declaration
+ // otherwise it could be an expression list...
+ | expressionList
+ )?
+ {#forInit = #(#[FOR_INIT,"FOR_INIT"],#forInit);}
+ ;
+
+forCond
+ : (expression)?
+ {#forCond = #(#[FOR_CONDITION,"FOR_CONDITION"],#forCond);}
+ ;
+
+forIter
+ : (expressionList)?
+ {#forIter = #(#[FOR_ITERATOR,"FOR_ITERATOR"],#forIter);}
+ ;
+
+// an exception handler try/catch block
+tryBlock
+ : "try"^ compoundStatement
+ (handler)*
+ ( finallyClause )?
+ ;
+
+finallyClause
+ : "finally"^ compoundStatement
+ ;
+
+// an exception handler
+handler
+ : "catch"^ LPAREN! parameterDeclaration RPAREN! compoundStatement
+ ;
+
+
+// expressions
+// Note that most of these expressions follow the pattern
+// thisLevelExpression :
+// nextHigherPrecedenceExpression
+// (OPERATOR nextHigherPrecedenceExpression)*
+// which is a standard recursive definition for a parsing an expression.
+// The operators in java have the following precedences:
+// lowest (13) = *= /= %= += -= <<= >>= >>>= &= ^= |=
+// (12) ?:
+// (11) ||
+// (10) &&
+// ( 9) |
+// ( 8) ^
+// ( 7) &
+// ( 6) == !=
+// ( 5) < <= > >=
+// ( 4) << >>
+// ( 3) +(binary) -(binary)
+// ( 2) * / %
+// ( 1) ++ -- +(unary) -(unary) ~ ! (type)
+// [] () (method call) . (dot -- identifier qualification)
+// new () (explicit parenthesis)
+//
+// the last two are not usually on a precedence chart; I put them in
+// to point out that new has a higher precedence than '.', so you
+// can validy use
+// new Frame().show()
+//
+// Note that the above precedence levels map to the rules below...
+// Once you have a precedence chart, writing the appropriate rules as below
+// is usually very straightfoward
+
+
+
+// the mother of all expressions
+expression
+ : assignmentExpression
+ {#expression = #(#[EXPR,"EXPR"],#expression);}
+ ;
+
+
+// This is a list of expressions.
+expressionList
+ : expression (COMMA! expression)*
+ {#expressionList = #(#[ELIST,"ELIST"], expressionList);}
+ ;
+
+
+// assignment expression (level 13)
+assignmentExpression
+ : conditionalExpression
+ ( ( ASSIGN^
+ | PLUS_ASSIGN^
+ | MINUS_ASSIGN^
+ | STAR_ASSIGN^
+ | DIV_ASSIGN^
+ | MOD_ASSIGN^
+ | SR_ASSIGN^
+ | BSR_ASSIGN^
+ | SL_ASSIGN^
+ | BAND_ASSIGN^
+ | BXOR_ASSIGN^
+ | BOR_ASSIGN^
+ )
+ assignmentExpression
+ )?
+ ;
+
+
+// conditional test (level 12)
+conditionalExpression
+ : logicalOrExpression
+ ( QUESTION^ assignmentExpression COLON! conditionalExpression )?
+ ;
+
+
+// logical or (||) (level 11)
+logicalOrExpression
+ : logicalAndExpression (LOR^ logicalAndExpression)*
+ ;
+
+
+// logical and (&&) (level 10)
+logicalAndExpression
+ : inclusiveOrExpression (LAND^ inclusiveOrExpression)*
+ ;
+
+
+// bitwise or non-short-circuiting or (|) (level 9)
+inclusiveOrExpression
+ : exclusiveOrExpression (BOR^ exclusiveOrExpression)*
+ ;
+
+
+// exclusive or (^) (level 8)
+exclusiveOrExpression
+ : andExpression (BXOR^ andExpression)*
+ ;
+
+
+// bitwise or non-short-circuiting and (&) (level 7)
+andExpression
+ : equalityExpression (BAND^ equalityExpression)*
+ ;
+
+
+// equality/inequality (==/!=) (level 6)
+equalityExpression
+ : relationalExpression ((NOT_EQUAL^ | EQUAL^) relationalExpression)*
+ ;
+
+
+// boolean relational expressions (level 5)
+relationalExpression
+ : shiftExpression
+ ( ( ( LT^
+ | GT^
+ | LE^
+ | GE^
+ )
+ shiftExpression
+ )*
+ | "instanceof"^ typeSpec[true]
+ )
+ ;
+
+
+// bit shift expressions (level 4)
+shiftExpression
+ : additiveExpression ((SL^ | SR^ | BSR^) additiveExpression)*
+ ;
+
+
+// binary addition/subtraction (level 3)
+additiveExpression
+ : multiplicativeExpression ((PLUS^ | MINUS^) multiplicativeExpression)*
+ ;
+
+
+// multiplication/division/modulo (level 2)
+multiplicativeExpression
+ : unaryExpression ((STAR^ | DIV^ | MOD^ ) unaryExpression)*
+ ;
+
+unaryExpression
+ : INC^ unaryExpression
+ | DEC^ unaryExpression
+ | MINUS^ {#MINUS.setType(UNARY_MINUS);} unaryExpression
+ | PLUS^ {#PLUS.setType(UNARY_PLUS);} unaryExpression
+ | unaryExpressionNotPlusMinus
+ ;
+
+unaryExpressionNotPlusMinus
+ : BNOT^ unaryExpression
+ | LNOT^ unaryExpression
+
+ | ( // subrule allows option to shut off warnings
+ options {
+ // "(int" ambig with postfixExpr due to lack of sequence
+ // info in linear approximate LL(k). It's ok. Shut up.
+ generateAmbigWarnings=false;
+ }
+ : // If typecast is built in type, must be numeric operand
+ // Also, no reason to backtrack if type keyword like int, float...
+ lpb:LPAREN^ {#lpb.setType(TYPECAST);} builtInTypeSpec[true] RPAREN!
+ unaryExpression
+
+ // Have to backtrack to see if operator follows. If no operator
+ // follows, it's a typecast. No semantic checking needed to parse.
+ // if it _looks_ like a cast, it _is_ a cast; else it's a "(expr)"
+ | (LPAREN classTypeSpec[true] RPAREN unaryExpressionNotPlusMinus)=>
+ lp:LPAREN^ {#lp.setType(TYPECAST);} classTypeSpec[true] RPAREN!
+ unaryExpressionNotPlusMinus
+
+ | postfixExpression
+ )
+ ;
+
+// qualified names, array expressions, method invocation, post inc/dec
+postfixExpression
+ :
+ /*
+ "this"! lp1:LPAREN^ argList RPAREN!
+ {#lp1.setType(CTOR_CALL);}
+
+ | "super"! lp2:LPAREN^ argList RPAREN!
+ {#lp2.setType(SUPER_CTOR_CALL);}
+ |
+ */
+ primaryExpression
+
+ (
+ /*
+ options {
+ // the use of postfixExpression in SUPER_CTOR_CALL adds DOT
+ // to the lookahead set, and gives loads of false non-det
+ // warnings.
+ // shut them off.
+ generateAmbigWarnings=false;
+ }
+ : */
+ DOT^ IDENT
+ ( lp:LPAREN^ {#lp.setType(METHOD_CALL);}
+ argList
+ RPAREN!
+ )?
+ | DOT^ "this"
+
+ | DOT^ "super"
+ ( // (new Outer()).super() (create enclosing instance)
+ lp3:LPAREN^ argList RPAREN!
+ {#lp3.setType(SUPER_CTOR_CALL);}
+ | DOT^ IDENT
+ ( lps:LPAREN^ {#lps.setType(METHOD_CALL);}
+ argList
+ RPAREN!
+ )?
+ )
+ | DOT^ newExpression
+ | lb:LBRACK^ {#lb.setType(INDEX_OP);} expression RBRACK!
+ )*
+
+ ( // possibly add on a post-increment or post-decrement.
+ // allows INC/DEC on too much, but semantics can check
+ in:INC^ {#in.setType(POST_INC);}
+ | de:DEC^ {#de.setType(POST_DEC);}
+ )?
+ ;
+
+// the basic element of an expression
+primaryExpression
+ : identPrimary ( options {greedy=true;} : DOT^ "class" )?
+ | constant
+ | "true"
+ | "false"
+ | "null"
+ | newExpression
+ | "this"
+ | "super"
+ | LPAREN! assignmentExpression RPAREN!
+ // look for int.class and int[].class
+ | builtInType
+ ( lbt:LBRACK^ {#lbt.setType(ARRAY_DECLARATOR);} RBRACK! )*
+ DOT^ "class"
+ ;
+
+/** Match a, a.b.c refs, a.b.c(...) refs, a.b.c[], a.b.c[].class,
+ * and a.b.c.class refs. Also this(...) and super(...). Match
+ * this or super.
+ */
+identPrimary
+ : IDENT
+ (
+ options {
+ // .ident could match here or in postfixExpression.
+ // We do want to match here. Turn off warning.
+ greedy=true;
+ }
+ : DOT^ IDENT
+ )*
+ (
+ options {
+ // ARRAY_DECLARATOR here conflicts with INDEX_OP in
+ // postfixExpression on LBRACK RBRACK.
+ // We want to match [] here, so greedy. This overcomes
+ // limitation of linear approximate lookahead.
+ greedy=true;
+ }
+ : ( lp:LPAREN^ {#lp.setType(METHOD_CALL);} argList RPAREN! )
+ | ( options {greedy=true;} :
+ lbc:LBRACK^ {#lbc.setType(ARRAY_DECLARATOR);} RBRACK!
+ )+
+ )?
+ ;
+
+/** object instantiation.
+ * Trees are built as illustrated by the following input/tree pairs:
+ *
+ * new T()
+ *
+ * new
+ * |
+ * T -- ELIST
+ * |
+ * arg1 -- arg2 -- .. -- argn
+ *
+ * new int[]
+ *
+ * new
+ * |
+ * int -- ARRAY_DECLARATOR
+ *
+ * new int[] {1,2}
+ *
+ * new
+ * |
+ * int -- ARRAY_DECLARATOR -- ARRAY_INIT
+ * |
+ * EXPR -- EXPR
+ * | |
+ * 1 2
+ *
+ * new int[3]
+ * new
+ * |
+ * int -- ARRAY_DECLARATOR
+ * |
+ * EXPR
+ * |
+ * 3
+ *
+ * new int[1][2]
+ *
+ * new
+ * |
+ * int -- ARRAY_DECLARATOR
+ * |
+ * ARRAY_DECLARATOR -- EXPR
+ * | |
+ * EXPR 1
+ * |
+ * 2
+ *
+ */
+newExpression
+ : "new"^ type
+ ( LPAREN! argList RPAREN! (classBlock)?
+
+ //java 1.1
+ // Note: This will allow bad constructs like
+ // new int[4][][3] {exp,exp}.
+ // There needs to be a semantic check here...
+ // to make sure:
+ // a) [ expr ] and [ ] are not mixed
+ // b) [ expr ] and an init are not used together
+
+ | newArrayDeclarator (arrayInitializer)?
+ )
+ ;
+
+argList
+ : ( expressionList
+ | /*nothing*/
+ {#argList = #[ELIST,"ELIST"];}
+ )
+ ;
+
+newArrayDeclarator
+ : (
+ // CONFLICT:
+ // newExpression is a primaryExpression which can be
+ // followed by an array index reference. This is ok,
+ // as the generated code will stay in this loop as
+ // long as it sees an LBRACK (proper behavior)
+ options {
+ warnWhenFollowAmbig = false;
+ }
+ :
+ lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);}
+ (expression)?
+ RBRACK!
+ )+
+ ;
+
+constant
+ : NUM_INT
+ | CHAR_LITERAL
+ | STRING_LITERAL
+ | NUM_FLOAT
+ | NUM_LONG
+ | NUM_DOUBLE
+ ;
+
+
+//----------------------------------------------------------------------------
+// The Java scanner
+//----------------------------------------------------------------------------
+class JavaLexer extends Lexer;
+
+options {
+ exportVocab=Java; // call the vocabulary "Java"
+ testLiterals=false; // don't automatically test for literals
+ k=4; // four characters of lookahead
+ charVocabulary='\u0003'..'\uFFFF';
+ // without inlining some bitset tests, couldn't do unicode;
+ // I need to make ANTLR generate smaller bitsets; see
+ // bottom of JavaLexer.java
+ codeGenBitsetTestThreshold=20;
+}
+
+
+
+// OPERATORS
+QUESTION : '?' ;
+LPAREN : '(' ;
+RPAREN : ')' ;
+LBRACK : '[' ;
+RBRACK : ']' ;
+LCURLY : '{' ;
+RCURLY : '}' ;
+COLON : ':' ;
+COMMA : ',' ;
+//DOT : '.' ;
+ASSIGN : '=' ;
+EQUAL : "==" ;
+LNOT : '!' ;
+BNOT : '~' ;
+NOT_EQUAL : "!=" ;
+DIV : '/' ;
+DIV_ASSIGN : "/=" ;
+PLUS : '+' ;
+PLUS_ASSIGN : "+=" ;
+INC : "++" ;
+MINUS : '-' ;
+MINUS_ASSIGN : "-=" ;
+DEC : "--" ;
+STAR : '*' ;
+STAR_ASSIGN : "*=" ;
+MOD : '%' ;
+MOD_ASSIGN : "%=" ;
+SR : ">>" ;
+SR_ASSIGN : ">>=" ;
+BSR : ">>>" ;
+BSR_ASSIGN : ">>>=" ;
+GE : ">=" ;
+GT : ">" ;
+SL : "<<" ;
+SL_ASSIGN : "<<=" ;
+LE : "<=" ;
+LT : '<' ;
+BXOR : '^' ;
+BXOR_ASSIGN : "^=" ;
+BOR : '|' ;
+BOR_ASSIGN : "|=" ;
+LOR : "||" ;
+BAND : '&' ;
+BAND_ASSIGN : "&=" ;
+LAND : "&&" ;
+SEMI : ';' ;
+
+
+// Whitespace -- ignored
+WS : ( ' '
+ | '\t'
+ | '\f'
+ // handle newlines
+ | ( options {generateAmbigWarnings=false;}
+ : "\r\n" // Evil DOS
+ | '\r' // Macintosh
+ | '\n' // Unix (the right way)
+ )
+ { newline(); }
+ )+
+ { _ttype = Token.SKIP; }
+ ;
+
+// Single-line comments
+SL_COMMENT
+ : "//"
+ (~('\n'|'\r'))* ('\n'|'\r'('\n')?)
+ {$setType(Token.SKIP); newline();}
+ ;
+
+// multiple-line comments
+ML_COMMENT
+ : "/*"
+ ( /* '\r' '\n' can be matched in one alternative or by matching
+ '\r' in one iteration and '\n' in another. I am trying to
+ handle any flavor of newline that comes in, but the language
+ that allows both "\r\n" and "\r" and "\n" to all be valid
+ newline is ambiguous. Consequently, the resulting grammar
+ must be ambiguous. I'm shutting this warning off.
+ */
+ options {
+ generateAmbigWarnings=false;
+ }
+ :
+ { LA(2)!='/' }? '*'
+ | '\r' '\n' {newline();}
+ | '\r' {newline();}
+ | '\n' {newline();}
+ | ~('*'|'\n'|'\r')
+ )*
+ "*/"
+ {$setType(Token.SKIP);}
+ ;
+
+
+// character literals
+CHAR_LITERAL
+ : '\'' ( ESC | ~'\'' ) '\''
+ ;
+
+// string literals
+STRING_LITERAL
+ : '"' (ESC|~('"'|'\\'))* '"'
+ ;
+
+
+// escape sequence -- note that this is protected; it can only be called
+// from another lexer rule -- it will not ever directly return a token to
+// the parser
+// There are various ambiguities hushed in this rule. The optional
+// '0'...'9' digit matches should be matched here rather than letting
+// them go back to STRING_LITERAL to be matched. ANTLR does the
+// right thing by matching immediately; hence, it's ok to shut off
+// the FOLLOW ambig warnings.
+protected
+ESC
+ : '\\'
+ ( 'n'
+ | 'r'
+ | 't'
+ | 'b'
+ | 'f'
+ | '"'
+ | '\''
+ | '\\'
+ | ('u')+ HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
+ | '0'..'3'
+ (
+ options {
+ warnWhenFollowAmbig = false;
+ }
+ : '0'..'7'
+ (
+ options {
+ warnWhenFollowAmbig = false;
+ }
+ : '0'..'7'
+ )?
+ )?
+ | '4'..'7'
+ (
+ options {
+ warnWhenFollowAmbig = false;
+ }
+ : '0'..'7'
+ )?
+ )
+ ;
+
+
+// hexadecimal digit (again, note it's protected!)
+protected
+HEX_DIGIT
+ : ('0'..'9'|'A'..'F'|'a'..'f')
+ ;
+
+
+// a dummy rule to force vocabulary to be all characters (except special
+// ones that ANTLR uses internally (0 to 2)
+protected
+VOCAB
+ : '\3'..'\377'
+ ;
+
+
+// an identifier. Note that testLiterals is set to true! This means
+// that after we match the rule, we look in the literals table to see
+// if it's a literal or really an identifer
+IDENT
+ options {testLiterals=true;}
+ : ('a'..'z'|'A'..'Z'|'_'|'$') ('a'..'z'|'A'..'Z'|'_'|'0'..'9'|'$')*
+ ;
+
+
+// a numeric literal
+NUM_INT
+ {boolean isDecimal=false; Token t=null;}
+ : '.' {_ttype = DOT;}
+ ( ('0'..'9')+ (EXPONENT)? (f1:FLOAT_SUFFIX {t=f1;})?
+ {
+ if (t != null && t.getText().toUpperCase().indexOf('F')>=0) {
+ _ttype = NUM_FLOAT;
+ }
+ else {
+ _ttype = NUM_DOUBLE; // assume double
+ }
+ }
+ )?
+
+ | ( '0' {isDecimal = true;} // special case for just '0'
+ ( ('x'|'X')
+ ( // hex
+ // the 'e'|'E' and float suffix stuff look
+ // like hex digits, hence the (...)+ doesn't
+ // know when to stop: ambig. ANTLR resolves
+ // it correctly by matching immediately. It
+ // is therefor ok to hush warning.
+ options {
+ warnWhenFollowAmbig=false;
+ }
+ : HEX_DIGIT
+ )+
+ | ('0'..'7')+ // octal
+ )?
+ | ('1'..'9') ('0'..'9')* {isDecimal=true;} // non-zero decimal
+ )
+ ( ('l'|'L') { _ttype = NUM_LONG; }
+
+ // only check to see if it's a float if looks like decimal so far
+ | {isDecimal}?
+ ( '.' ('0'..'9')* (EXPONENT)? (f2:FLOAT_SUFFIX {t=f2;})?
+ | EXPONENT (f3:FLOAT_SUFFIX {t=f3;})?
+ | f4:FLOAT_SUFFIX {t=f4;}
+ )
+ {
+ if (t != null && t.getText().toUpperCase() .indexOf('F') >= 0) {
+ _ttype = NUM_FLOAT;
+ }
+ else {
+ _ttype = NUM_DOUBLE; // assume double
+ }
+ }
+ )?
+ ;
+
+
+// a couple protected methods to assist in matching floating point numbers
+protected
+EXPONENT
+ : ('e'|'E') ('+'|'-')? ('0'..'9')+
+ ;
+
+
+protected
+FLOAT_SUFFIX
+ : 'f'|'F'|'d'|'D'
+ ;
+
diff --git a/app/src/antlr/java/java.g.java15 b/app/src/antlr/java/java.g.java15
new file mode 100644
index 000000000..b119cd35f
--- /dev/null
+++ b/app/src/antlr/java/java.g.java15
@@ -0,0 +1,2002 @@
+header
+{
+package de.hunsicker.jalopy.language.antlr;
+
+import de.hunsicker.jalopy.language.antlr.JavaNode;
+import de.hunsicker.jalopy.language.JavaNodeHelper;
+}
+
+/** Java 1.5 Recognizer
+ *
+ * Run 'java Main [-showtree] directory-full-of-java-files'
+ *
+ * [The -showtree option pops up a Swing frame that shows
+ * the JavaNode constructed from the parser.]
+ *
+ * Run 'java Main '
+ *
+ * Contributing authors:
+ * John Mitchell johnm@non.net
+ * Terence Parr parrt@magelang.com
+ * John Lilley jlilley@empathy.com
+ * Scott Stanchfield thetick@magelang.com
+ * Markus Mohnen mohnen@informatik.rwth-aachen.de
+ * Peter Williams pete.williams@sun.com
+ * Allan Jacobs Allan.Jacobs@eng.sun.com
+ * Steve Messick messick@redhills.com
+ * John Pybus john@pybus.org
+ *
+ * Version 1.00 December 9, 1997 -- initial release
+ * Version 1.01 December 10, 1997
+ * fixed bug in octal def (0..7 not 0..8)
+ * Version 1.10 August 1998 (parrt)
+ * added tree construction
+ * fixed definition of WS,comments for mac,pc,unix newlines
+ * added unary plus
+ * Version 1.11 (Nov 20, 1998)
+ * Added "shutup" option to turn off last ambig warning.
+ * Fixed inner class def to allow named class defs as statements
+ * synchronized requires compound not simple statement
+ * add [] after builtInType DOT class in primaryExpression
+ * "const" is reserved but not valid..removed from modifiers
+ * Version 1.12 (Feb 2, 1999)
+ * Changed LITERAL_xxx to xxx in tree grammar.
+ * Updated java.g to use tokens {...} now for 2.6.0 (new feature).
+ *
+ * Version 1.13 (Apr 23, 1999)
+ * Didn't have (stat)? for else clause in tree parser.
+ * Didn't gen ASTs for interface extends. Updated tree parser too.
+ * Updated to 2.6.0.
+ * Version 1.14 (Jun 20, 1999)
+ * Allowed final/abstract on local classes.
+ * Removed local interfaces from methods
+ * Put instanceof precedence where it belongs...in relationalExpr
+ * It also had expr not type as arg; fixed it.
+ * Missing ! on SEMI in classBlock
+ * fixed: (expr) + "string" was parsed incorrectly (+ as unary plus).
+ * fixed: didn't like Object[].class in parser or tree parser
+ * Version 1.15 (Jun 26, 1999)
+ * Screwed up rule with instanceof in it. :( Fixed.
+ * Tree parser didn't like (expr).something; fixed.
+ * Allowed multiple inheritance in tree grammar. oops.
+ * Version 1.16 (August 22, 1999)
+ * Extending an interface built a wacky tree: had extra EXTENDS.
+ * Tree grammar didn't allow multiple superinterfaces.
+ * Tree grammar didn't allow empty var initializer: {}
+ * Version 1.17 (October 12, 1999)
+ * ESC lexer rule allowed 399 max not 377 max.
+ * java.tree.g didn't handle the expression of synchronized
+ * statements.
+ * Version 1.18 (August 12, 2001)
+ * Terence updated to Java 2 Version 1.3 by
+ * observing/combining work of Allan Jacobs and Steve
+ * Messick. Handles 1.3 src. Summary:
+ * o primary didn't include boolean.class kind of thing
+ * o constructor calls parsed explicitly now:
+ * see explicitConstructorInvocation
+ * o add strictfp modifier
+ * o missing objBlock after new expression in tree grammar
+ * o merged local class definition alternatives, moved after declaration
+ * o fixed problem with ClassName.super.field
+ * o reordered some alternatives to make things more efficient
+ * o long and double constants were not differentiated from int/float
+ * o whitespace rule was inefficient: matched only one char
+ * o add an examples directory with some nasty 1.3 cases
+ * o made Main.java use buffered IO and a Reader for Unicode support
+ * o supports UNICODE?
+ * Using Unicode charVocabulay makes code file big, but only
+ * in the bitsets at the end. I need to make ANTLR generate
+ * unicode bitsets more efficiently.
+ * Version 1.19 (April 25, 2002)
+ * Terence added in nice fixes by John Pybus concerning floating
+ * constants and problems with super() calls. John did a nice
+ * reorg of the primary/postfix expression stuff to read better
+ * and makes f.g.super() parse properly (it was METHOD_CALL not
+ * a SUPER_CTOR_CALL). Also:
+ *
+ * o "finally" clause was a root...made it a child of "try"
+ * o Added stuff for asserts too for Java 1.4, but *commented out*
+ * as it is not backward compatible.
+ *
+ * Version 1.20 (October 27, 2002)
+ *
+ * Terence ended up reorging John Pybus' stuff to
+ * remove some nondeterminisms and some syntactic predicates.
+ * Note that the grammar is stricter now; e.g., this(...) must
+ * be the first statement.
+ *
+ * Trinary ?: operator wasn't working as array name:
+ * (isBig ? bigDigits : digits)[i];
+ *
+ * Checked parser/tree parser on source for
+ * Resin-2.0.5, jive-2.1.1, jdk 1.3.1, Lucene, antlr 2.7.2a4,
+ * and the 110k-line jGuru server source.
+ *
+ * Version 1.21 (October 17, 2003)
+ * Fixed lots of problems including:
+ * Ray Waldin: add typeDefinition to interfaceBlock in java.tree.g
+ * He found a problem/fix with floating point that start with 0
+ * Ray also fixed problem that (int.class) was not recognized.
+ * Thorsten van Ellen noticed that \n are allowed incorrectly in strings.
+ * TJP fixed CHAR_LITERAL analogously.
+ *
+ * Version 1.21.2 (March, 2003)
+ * Changes by Matt Quail to support generics (as per JDK1.5/JSR14)
+ * Notes:
+ * o We only allow the "extends" keyword and not the "implements"
+ * keyword, since thats what JSR14 seems to imply.
+ * o Thanks to Monty Zukowski for his help on the antlr-interest
+ * mail list.
+ * o Thanks to Alan Eliasen for testing the grammar over his
+ * Fink source base
+ *
+ * Version 1.22 (July, 2004)
+ * Changes by Michael Studman to support Java 1.5 language extensions
+ * Notes:
+ * o Added support for annotations types
+ * o Finished off Matt Quail's generics enhancements to support bound type arguments
+ * o Added support for new for statement syntax
+ * o Added support for static import syntax
+ * o Added support for enum types
+ * o Tested against JDK 1.5 source base and source base of jdigraph project
+ * o Thanks to Matt Quail for doing the hard part by doing most of the generics work
+ *
+ * Version 1.22.1 (July 28, 2004)
+ * Bug/omission fixes for Java 1.5 language support
+ * o Fixed tree structure bug with classOrInterface - thanks to Pieter Vangorpto for
+ * spotting this
+ * o Fixed bug where incorrect handling of SR and BSR tokens would cause type
+ * parameters to be recognised as type arguments.
+ * o Enabled type parameters on constructors, annotations on enum constants
+ * and package definitions
+ * o Fixed problems when parsing if ((char.class.equals(c))) {} - solution by Matt Quail at Cenqua
+ *
+ * Version 1.22.2 (July 28, 2004)
+ * Slight refactoring of Java 1.5 language support
+ * o Refactored for/"foreach" productions so that original literal "for" literal
+ * is still used but the for sub-clauses vary by token type
+ * o Fixed bug where type parameter was not included in generic constructor's branch of AST
+ *
+ * Version 1.22.3 (August 26, 2004)
+ * Bug fixes as identified by Michael Stahl; clean up of tabs/spaces
+ * and other refactorings
+ * o Fixed typeParameters omission in identPrimary and newStatement
+ * o Replaced GT reconcilliation code with simple semantic predicate
+ * o Adapted enum/assert keyword checking support from Michael Stahl's java15 grammar
+ * o Refactored typeDefinition production and field productions to reduce duplication
+ *
+ * Version 1.22.4 (October 21, 2004)
+ * Small bux fixes
+ * o Added typeArguments to explicitConstructorInvocation, e.g. new MyParameterised()
+ * o Added typeArguments to postfixExpression productions for anonymous inner class super
+ * constructor invocation, e.g. new Outer().super()
+ * o Fixed bug in array declarations identified by Geoff Roy
+ *
+ * This grammar is in the PUBLIC DOMAIN
+ */
+
+class InternalJavaParser extends Parser;
+options {
+ k = 2; // two token lookahead
+ exportVocab=Java; // Call its vocabulary "Java"
+ codeGenMakeSwitchThreshold = 2; // Some optimizations
+ codeGenBitsetTestThreshold = 3;
+ defaultErrorHandler = false; // Don't generate parser error handlers
+ buildAST = true;
+// classHeaderSuffix = "Parser";
+ importVocab = Common;
+ ASTLabelType = JavaNode;
+// useTokenPrefix = true;
+ // This class is abstract
+ classHeaderPrefix = "public abstract";
+
+}
+tokens {
+ BLOCK; MODIFIERS; OBJBLOCK; SLIST; CTOR_DEF; METHOD_DEF; VARIABLE_DEF;
+ INSTANCE_INIT; STATIC_INIT; TYPE; CLASS_DEF; INTERFACE_DEF;
+ PACKAGE_DEF; ARRAY_DECLARATOR; EXTENDS_CLAUSE; IMPLEMENTS_CLAUSE;
+ PARAMETERS; PARAMETER_DEF; LABELED_STAT; TYPECAST; INDEX_OP;
+ POST_INC; POST_DEC; METHOD_CALL; EXPR; ARRAY_INIT;
+ IMPORT; UNARY_MINUS; UNARY_PLUS; CASE_GROUP; ELIST; FOR_INIT; FOR_CONDITION;
+ FOR_ITERATOR; EMPTY_STAT; FINAL="final"; ABSTRACT="abstract";
+ STRICTFP="strictfp"; SUPER_CTOR_CALL; CTOR_CALL; VARIABLE_PARAMETER_DEF;
+ STATIC_IMPORT; ENUM_DEF; ENUM_CONSTANT_DEF; FOR_EACH_CLAUSE; ANNOTATION_DEF; ANNOTATIONS;
+ ANNOTATION; ANNOTATION_MEMBER_VALUE_PAIR; ANNOTATION_FIELD_DEF; ANNOTATION_ARRAY_INIT;
+ TYPE_ARGUMENTS; TYPE_ARGUMENT; TYPE_PARAMETERS; TYPE_PARAMETER; WILDCARD_TYPE;
+ TYPE_UPPER_BOUNDS; TYPE_LOWER_BOUNDS;
+
+ ROOT;CASESLIST;SEPARATOR_COMMENT;BOF;SYNBLOCK;SPECIAL_COMMENT;
+
+}
+
+{
+ /**
+ * Counts the number of LT seen in the typeArguments production.
+ * It is used in semantic predicates to ensure we have seen
+ * enough closing '>' characters; which actually may have been
+ * either GT, SR or BSR tokens.
+ */
+ private int ltCounter = 0;
+
+ protected abstract void attachStuff(JavaNode[] nodes) throws TokenStreamIOException;
+
+}
+
+// Compilation Unit: In Java, this is a single file. This is the start
+// rule for this parser compilationUnit
+parse
+ {
+ JavaNode root = (JavaNode) getASTFactory().create();
+ root.setType(JavaTokenTypes.ROOT);
+ root.setText(getFilename());
+ currentAST.root = root;
+ }
+
+ : // A compilation unit starts with an optional package definition
+ ( (annotations "package")=> packageDefinition
+ | /* nothing */
+ )
+
+ // Next we have a series of zero or more import statements
+ ( importDefinition )*
+
+ // Wrapping things up with any number of class or interface
+ // definitions
+ ( typeDefinition )*
+
+ EOF
+ ;
+
+
+// Package statement: optional annotations followed by "package" then the package identifier.
+packageDefinition
+ options {defaultErrorHandler = true;} // let ANTLR handle errors
+ : annotations p:"package"^ {#p.setType(PACKAGE_DEF);} identifier SEMI
+ ;
+
+
+// Import statement: import followed by a package or class name
+importDefinition
+ options {defaultErrorHandler = true;}
+ { boolean isStatic = false; }
+ : i:"import"^ {#i.setType(IMPORT);} ( "static"! {#i.setType(STATIC_IMPORT);} )? identifierStar SEMI
+ ;
+
+// A type definition is either a class, interface, enum or annotation with possible additional semis.
+typeDefinition
+ options {defaultErrorHandler = true;}
+ : m:modifiers!
+ typeDefinitionInternal[#m]
+ | SEMI
+ ;
+
+// Protected type definitions production for reuse in other productions
+protected typeDefinitionInternal[JavaNode mods]
+ : classDefinition[#mods] // inner class
+ | interfaceDefinition[#mods] // inner interface
+ | enumDefinition[#mods] // inner enum
+ | annotationDefinition[#mods] // inner annotation
+ ;
+
+// A declaration is the creation of a reference or primitive-type variable
+// Create a separate Type/Var tree for each var in the var list.
+declaration!
+ : m:modifiers t:typeSpec[false] v:variableDefinitions[#m,#t]
+ {#declaration = #v;}
+ ;
+
+// A type specification is a type name with possible brackets afterwards
+// (which would make it an array type).
+typeSpec[boolean addImagNode]
+ : classTypeSpec[addImagNode]
+ | builtInTypeSpec[addImagNode]
+ ;
+
+// A class type specification is a class type with either:
+// - possible brackets afterwards
+// (which would make it an array type).
+// - generic type arguments after
+classTypeSpec[boolean addImagNode]
+ : classOrInterfaceType[false]
+ (options{greedy=true;}: // match as many as possible
+ lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK!
+ )*
+ {
+ if ( addImagNode ) {
+ #classTypeSpec = #(#[TYPE,"TYPE"], #classTypeSpec);
+ }
+ }
+ ;
+
+// A non-built in type name, with possible type parameters
+classOrInterfaceType[boolean addImagNode]
+ : IDENT^ (typeArguments)?
+ (options{greedy=true;}: // match as many as possible
+ DOT^
+ IDENT (typeArguments)?
+ )*
+ {
+ if ( addImagNode ) {
+ #classOrInterfaceType = #(#[TYPE,"TYPE"], #classOrInterfaceType);
+ }
+ }
+ ;
+
+// A specialised form of typeSpec where built in types must be arrays
+typeArgumentSpec
+ : classTypeSpec[true]
+ | builtInTypeArraySpec[true]
+ ;
+
+// A generic type argument is a class type, a possibly bounded wildcard type or a built-in type array
+typeArgument
+ : ( typeArgumentSpec
+ | wildcardType
+ )
+ {#typeArgument = #(#[TYPE_ARGUMENT,"TYPE_ARGUMENT"], #typeArgument);}
+ ;
+
+// Wildcard type indicating all types (with possible constraint)
+wildcardType
+ : q:QUESTION^ {#q.setType(WILDCARD_TYPE);}
+ (("extends" | "super")=> typeArgumentBounds)?
+ ;
+
+// Type arguments to a class or interface type
+typeArguments
+{int currentLtLevel = 0;}
+ :
+ {currentLtLevel = ltCounter;}
+ LT! {ltCounter++;}
+ typeArgument
+ (options{greedy=true;}: // match as many as possible
+ {inputState.guessing !=0 || ltCounter == currentLtLevel + 1}?
+ COMMA typeArgument
+ )*
+
+ ( // turn warning off since Antlr generates the right code,
+ // plus we have our semantic predicate below
+ options{generateAmbigWarnings=false;}:
+ typeArgumentsOrParametersEnd
+ )?
+
+ // make sure we have gobbled up enough '>' characters
+ // if we are at the "top level" of nested typeArgument productions
+ {(currentLtLevel != 0) || ltCounter == currentLtLevel}?
+
+ {#typeArguments = #(#[TYPE_ARGUMENTS, "TYPE_ARGUMENTS"], #typeArguments);}
+ ;
+
+// this gobbles up *some* amount of '>' characters, and counts how many
+// it gobbled.
+protected typeArgumentsOrParametersEnd
+ : GT! {ltCounter-=1;}
+ | SR! {ltCounter-=2;}
+ | BSR! {ltCounter-=3;}
+ ;
+
+// Restriction on wildcard types based on super class or derrived class
+typeArgumentBounds
+ {boolean isUpperBounds = false;}
+ :
+ ( "extends"! {isUpperBounds=true;} | "super"! ) classOrInterfaceType[false]
+ {
+ if (isUpperBounds)
+ {
+ #typeArgumentBounds = #(#[TYPE_UPPER_BOUNDS,"TYPE_UPPER_BOUNDS"], #typeArgumentBounds);
+ }
+ else
+ {
+ #typeArgumentBounds = #(#[TYPE_LOWER_BOUNDS,"TYPE_LOWER_BOUNDS"], #typeArgumentBounds);
+ }
+ }
+ ;
+
+// A builtin type array specification is a builtin type with brackets afterwards
+builtInTypeArraySpec[boolean addImagNode]
+ : builtInType
+ (options{greedy=true;}: // match as many as possible
+ lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK!
+ )+
+
+ {
+ if ( addImagNode ) {
+ #builtInTypeArraySpec = #(#[TYPE,"TYPE"], #builtInTypeArraySpec);
+ }
+ }
+ ;
+
+// A builtin type specification is a builtin type with possible brackets
+// afterwards (which would make it an array type).
+builtInTypeSpec[boolean addImagNode]
+ : builtInType
+ (options{greedy=true;}: // match as many as possible
+ lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK!
+ )*
+ {
+ if ( addImagNode ) {
+ #builtInTypeSpec = #(#[TYPE,"TYPE"], #builtInTypeSpec);
+ }
+ }
+ ;
+
+// A type name. which is either a (possibly qualified and parameterized)
+// class name or a primitive (builtin) type
+type
+ : classOrInterfaceType[false]
+ | builtInType
+ ;
+
+// The primitive types.
+builtInType
+ : "void"
+ | "boolean"
+ | "byte"
+ | "char"
+ | "short"
+ | "int"
+ | "float"
+ | "long"
+ | "double"
+ ;
+
+// A (possibly-qualified) java identifier. We start with the first IDENT
+// and expand its name by adding dots and following IDENTS
+identifier
+ : IDENT ( DOT^ IDENT )*
+ ;
+
+identifierStar
+ : IDENT
+ ( DOT^ IDENT )*
+ ( DOT^ STAR )?
+ ;
+
+// A list of zero or more modifiers. We could have used (modifier)* in
+// place of a call to modifiers, but I thought it was a good idea to keep
+// this rule separate so they can easily be collected in a Vector if
+// someone so desires
+modifiers
+ :
+ (
+ //hush warnings since the semantic check for "@interface" solves the non-determinism
+ options{generateAmbigWarnings=false;}:
+
+ modifier
+ |
+ //Semantic check that we aren't matching @interface as this is not an annotation
+ //A nicer way to do this would be nice
+ {LA(1)==AT && !LT(2).getText().equals("interface")}? annotation
+ )*
+
+ {#modifiers = #([MODIFIERS, "MODIFIERS"], #modifiers);}
+ ;
+
+// modifiers for Java classes, interfaces, class/instance vars and methods
+modifier
+ : "private"
+ | "public"
+ | "protected"
+ | "static"
+ | "transient"
+ | "final"
+ | "abstract"
+ | "native"
+ | "threadsafe"
+ | "synchronized"
+ | "volatile"
+ | "strictfp"
+ ;
+
+annotation!
+ : a:AT i:identifier ( lp:LPAREN ( args:annotationArguments )? rp:RPAREN )?
+ {#annotation = #(#[ANNOTATION,"ANNOTATION"],a, i, lp, args, rp);}
+ ;
+
+annotations
+ : (annotation)*
+ {#annotations = #([ANNOTATIONS, "ANNOTATIONS"], #annotations);}
+ ;
+
+annotationArguments
+ : annotationMemberValueInitializer | anntotationMemberValuePairs
+ ;
+
+anntotationMemberValuePairs
+ : annotationMemberValuePair ( COMMA annotationMemberValuePair )*
+ ;
+
+annotationMemberValuePair!
+ : i:IDENT ASSIGN! v:annotationMemberValueInitializer
+ {#annotationMemberValuePair = #(#[ANNOTATION_MEMBER_VALUE_PAIR,"ANNOTATION_MEMBER_VALUE_PAIR"], i, v);}
+ ;
+
+annotationMemberValueInitializer
+ :
+ conditionalExpression | annotation | annotationMemberArrayInitializer
+ ;
+
+// This is an initializer used to set up an annotation member array.
+annotationMemberArrayInitializer
+ : lc:LCURLY^ {#lc.setType(ANNOTATION_ARRAY_INIT);}
+ ( annotationMemberArrayValueInitializer
+ (
+ // CONFLICT: does a COMMA after an initializer start a new
+ // initializer or start the option ',' at end?
+ // ANTLR generates proper code by matching
+ // the comma as soon as possible.
+ options {
+ warnWhenFollowAmbig = false;
+ }
+ :
+ COMMA annotationMemberArrayValueInitializer
+ )*
+ (COMMA)?
+ )?
+ RCURLY
+ ;
+
+// The two things that can initialize an annotation array element are a conditional expression
+// and an annotation (nested annotation array initialisers are not valid)
+annotationMemberArrayValueInitializer
+ : conditionalExpression
+ | annotation
+ ;
+
+superClassClause!
+ : ( "extends" c:classOrInterfaceType[false] )?
+ {#superClassClause = #(#[EXTENDS_CLAUSE,"EXTENDS_CLAUSE"],c);}
+ ;
+
+// Definition of a Java class
+classDefinition![JavaNode modifiers]
+ : c:"class" IDENT
+ // it _might_ have type paramaters
+ (tp:typeParameters)?
+ // it _might_ have a superclass...
+ sc:superClassClause
+ // it might implement some interfaces...
+ ic:implementsClause
+ // now parse the body of the class
+ cb:classBlock
+ {#classDefinition = #(#[CLASS_DEF,"CLASS_DEF"],
+ modifiers,IDENT,tp,sc,ic,cb);
+ attachStuff(new JavaNode[] {#classDefinition, modifiers, #c});
+ }
+ ;
+
+// Definition of a Java Interface
+interfaceDefinition![JavaNode modifiers]
+ : i:"interface" IDENT
+ // it _might_ have type paramaters
+ (tp:typeParameters)?
+ // it might extend some other interfaces
+ ie:interfaceExtends
+ // now parse the body of the interface (looks like a class...)
+ ib:interfaceBlock
+ {#interfaceDefinition = #(#[INTERFACE_DEF,"INTERFACE_DEF"],
+ modifiers,IDENT,tp,ie,ib);
+ attachStuff(new JavaNode[] {#interfaceDefinition, modifiers, #i});
+ }
+ ;
+
+enumDefinition![JavaNode modifiers]
+ : e:"enum" IDENT
+ // it might implement some interfaces...
+ ic:implementsClause
+ // now parse the body of the enum
+ eb:enumBlock
+ {#enumDefinition = #(#[ENUM_DEF,"ENUM_DEF"],
+ modifiers,IDENT,ic,eb);
+ attachStuff(new JavaNode[] {#enumDefinition, modifiers, #e});
+ }
+ ;
+
+annotationDefinition![JavaNode modifiers]
+ : a:AT "interface" IDENT
+ // now parse the body of the annotation
+ ab:annotationBlock
+ {#annotationDefinition = #(#[ANNOTATION_DEF,"ANNOTATION_DEF"],
+ modifiers,IDENT,ab);
+ attachStuff(new JavaNode[] {#annotationDefinition, modifiers, #a});
+ }
+ ;
+
+typeParameters
+{int currentLtLevel = 0;}
+ :
+ {currentLtLevel = ltCounter;}
+ LT {ltCounter++;}
+ typeParameter (COMMA typeParameter)*
+ (typeArgumentsOrParametersEnd)?
+
+ // make sure we have gobbled up enough '>' characters
+ // if we are at the "top level" of nested typeArgument productions
+ {(currentLtLevel != 0) || ltCounter == currentLtLevel}?
+
+ {#typeParameters = #(#[TYPE_PARAMETERS, "TYPE_PARAMETERS"], #typeParameters);}
+ ;
+
+typeParameter
+ :
+ // I'm pretty sure Antlr generates the right thing here:
+ (id:IDENT) ( options{generateAmbigWarnings=false;}: typeParameterBounds )?
+ {#typeParameter = #(#[TYPE_PARAMETER,"TYPE_PARAMETER"], #typeParameter);}
+ ;
+
+typeParameterBounds
+ :
+ "extends"! classOrInterfaceType[false]
+ (BAND classOrInterfaceType[false])*
+ {#typeParameterBounds = #(#[TYPE_UPPER_BOUNDS,"TYPE_UPPER_BOUNDS"], #typeParameterBounds);}
+ ;
+
+// This is the body of a class. You can have classFields and extra semicolons.
+classBlock
+ : lc:LCURLY^
+ ( classField | SEMI )*
+ RCURLY
+ { #lc.setType(OBJBLOCK);}
+ //{#classBlock = #([OBJBLOCK, "OBJBLOCK"], #classBlock);}
+ ;
+
+// This is the body of an interface. You can have interfaceField and extra semicolons.
+interfaceBlock
+ : lc:LCURLY^
+ ( interfaceField | SEMI )*
+ RCURLY
+ { #lc.setType(OBJBLOCK);}
+ //{#interfaceBlock = #([OBJBLOCK, "OBJBLOCK"], #interfaceBlock);}
+ ;
+
+// This is the body of an annotation. You can have annotation fields and extra semicolons,
+// That's about it (until you see what an annoation field is...)
+annotationBlock
+ : lc:LCURLY^
+ ( annotationField | SEMI )*
+ RCURLY
+ { #lc.setType(OBJBLOCK);}
+// {#annotationBlock = #([OBJBLOCK, "OBJBLOCK"], #annotationBlock);}
+ ;
+
+// This is the body of an enum. You can have zero or more enum constants
+// followed by any number of fields like a regular class
+enumBlock
+ : lc:LCURLY^
+ ( enumConstant ( options{greedy=true;}: COMMA! enumConstant )* ( COMMA! )? )?
+ ( SEMI! ( classField | SEMI! )* )?
+ RCURLY
+ { #lc.setType(OBJBLOCK);}
+// {#enumBlock = #([OBJBLOCK, "OBJBLOCK"], #enumBlock);}
+ ;
+
+// An annotation field
+annotationField!
+ : mods:modifiers
+ ( td:typeDefinitionInternal[#mods]
+ {#annotationField = #td;}
+ | t:typeSpec[false] // annotation field
+ ( i:IDENT // the name of the field
+
+ LPAREN RPAREN
+
+ rt:declaratorBrackets[#t]
+
+ ( "default" amvi:annotationMemberValueInitializer ) ?
+// { if (#d!=null) #d = #(d,#(amvi)); }
+
+ SEMI
+
+ {#annotationField =
+ #(#[ANNOTATION_FIELD_DEF,"ANNOTATION_FIELD_DEF"],
+ mods,
+ #(#[TYPE,"TYPE"],rt),
+ i,LPAREN,RPAREN,amvi,SEMI
+ );
+ attachStuff(new JavaNode[] {#annotationField, #mods, #t});
+ }
+ | v:variableDefinitions[#mods,#t] // typeVariableDefinitions
+ {
+ #annotationField = #v;
+ }
+ )
+ )
+ ;
+
+//An enum constant may have optional parameters and may have a
+//a class body
+enumConstant!
+ : an:annotations
+ i:IDENT
+ ( lp:LPAREN
+ a:argList
+ rp:RPAREN
+ )?
+ ( b:enumConstantBlock )?
+ {#enumConstant = #([ENUM_CONSTANT_DEF, "ENUM_CONSTANT_DEF"], an, i, lp,a,rp, b);}
+ ;
+
+//The class-like body of an enum constant
+enumConstantBlock
+ : LCURLY
+ ( enumConstantField | SEMI )*
+ RCURLY
+ {#enumConstantBlock = #([OBJBLOCK, "OBJBLOCK"], #enumConstantBlock);}
+ ;
+
+//An enum constant field is just like a class field but without
+//the posibility of a constructor definition or a static initializer
+enumConstantField!
+ : mods:modifiers
+ ( td:typeDefinitionInternal[#mods]
+ {#enumConstantField = #td;}
+
+ | // A generic method has the typeParameters before the return type.
+ // This is not allowed for variable definitions, but this production
+ // allows it, a semantic check could be used if you wanted.
+ (tp:typeParameters)? t:typeSpec[false] // method or variable declaration(s)
+ ( IDENT // the name of the method
+
+ // parse the formal parameter declarations.
+ LPAREN param:parameterDeclarationList RPAREN
+
+ rt:declaratorBrackets[#t]
+
+ // get the list of exceptions that this method is
+ // declared to throw
+ (tc:throwsClause)?
+
+ ( s2:compoundStatement | semim:SEMI )
+ {#enumConstantField = #(#[METHOD_DEF,"METHOD_DEF"],
+ mods,
+ tp,
+ #(#[TYPE,"TYPE"],rt),
+ IDENT,
+ param,
+ tc,
+ s2,
+ semim);
+ attachStuff(new JavaNode[] {#enumConstantField, #mods, #t});
+ }
+ | v:variableDefinitions[#mods,#t] // typeVariableDefinitions
+ {#enumConstantField = #v;
+ }
+ )
+ )
+
+ // "{ ... }" instance initializer
+ | s4:compoundStatement
+ {#enumConstantField = #(#[INSTANCE_INIT,"INSTANCE_INIT"], s4);
+ attachStuff(new JavaNode[] {#enumConstantField, #s4});
+ }
+ ;
+
+// An interface can extend several other interfaces...
+interfaceExtends
+ : (
+ e:"extends"!
+ classOrInterfaceType[false] ( COMMA! classOrInterfaceType[false] )*
+ )?
+ {#interfaceExtends = #(#[EXTENDS_CLAUSE,"EXTENDS_CLAUSE"],
+ #interfaceExtends);}
+ ;
+
+// A class can implement several interfaces...
+implementsClause
+ : (
+ i:"implements"! classOrInterfaceType[false] ( COMMA! classOrInterfaceType[false] )*
+ )?
+ {#implementsClause = #(#[IMPLEMENTS_CLAUSE,"IMPLEMENTS_CLAUSE"],
+ #implementsClause);}
+ ;
+
+// Now the various things that can be defined inside a class
+classField!
+ : // method, constructor, or variable declaration
+ mods:modifiers
+ ( td:typeDefinitionInternal[#mods]
+ {#classField = #td;}
+
+ | (tp:typeParameters)?
+ (
+ h:ctorHead s:constructorBody // constructor
+ {#classField = #(#[CTOR_DEF,"CTOR_DEF"], mods, tp, h, s);
+ attachStuff(new JavaNode[] {#classField, #mods, #h});
+ }
+
+ | // A generic method/ctor has the typeParameters before the return type.
+ // This is not allowed for variable definitions, but this production
+ // allows it, a semantic check could be used if you wanted.
+ t:typeSpec[false] // method or variable declaration(s)
+ ( IDENT // the name of the method
+
+ // parse the formal parameter declarations.
+ LPAREN param:parameterDeclarationList RPAREN
+
+ rt:declaratorBrackets[#t]
+
+ // get the list of exceptions that this method is
+ // declared to throw
+ (tc:throwsClause)?
+
+ ( s2:compoundStatement | semim:SEMI )
+ {#classField = #(#[METHOD_DEF,"METHOD_DEF"],
+ mods,
+ tp,
+ #(#[TYPE,"TYPE"],rt),
+ IDENT,
+ LPAREN,
+ param,
+ RPAREN,
+ tc,
+ s2,
+ semim);
+ attachStuff(new JavaNode[] {#classField, #mods, #t});
+ }
+ | v:variableDefinitions[#mods,#t] semi:SEMI!// typeVariableDefinitions
+ {
+ #classField = #v;
+
+ #classField.addChild(#semi);
+
+ AST next = #classField.getNextSibling();
+ // HACK for multiple variable declaration in one statement
+ // e.g float x, y, z;
+ // the semicolon will only be added to the first statement so
+ // we have to add it manually to all others
+ if (next != null)
+ {
+ AST ssemi = JavaNodeHelper.getFirstChild(#classField, JavaTokenTypes.SEMI);
+
+ for (AST var = next; var != null; var = var.getNextSibling())
+ {
+ var.addChild(astFactory.create(ssemi));
+ }
+ }
+
+
+ }
+ )
+ )
+ )
+
+ // "static { ... }" class initializer
+ | "static" s3:compoundStatement
+ {#classField = #(#[STATIC_INIT,"STATIC_INIT"], s3);
+ attachStuff(new JavaNode[] {#classField, #s3});
+ }
+
+ // "{ ... }" instance initializer
+ | s4:compoundStatement
+ {#classField = #(#[INSTANCE_INIT,"INSTANCE_INIT"], s4);
+ attachStuff(new JavaNode[] {#classField, #s4});
+ }
+ ;
+
+// Now the various things that can be defined inside a interface
+interfaceField!
+ : // method, constructor, or variable declaration
+ mods:modifiers
+ ( td:typeDefinitionInternal[#mods]
+ {#interfaceField = #td;}
+
+ | (tp:typeParameters)?
+ // A generic method has the typeParameters before the return type.
+ // This is not allowed for variable definitions, but this production
+ // allows it, a semantic check could be used if you want a more strict
+ // grammar.
+ t:typeSpec[false] // method or variable declaration(s)
+ ( IDENT // the name of the method
+
+ // parse the formal parameter declarations.
+ LPAREN param:parameterDeclarationList RPAREN
+
+ rt:declaratorBrackets[#t]
+
+ // get the list of exceptions that this method is
+ // declared to throw
+ (tc:throwsClause)?
+
+ SEMI
+
+ {#interfaceField = #(#[METHOD_DEF,"METHOD_DEF"],
+ mods,
+ tp,
+ #(#[TYPE,"TYPE"],rt),
+ IDENT,
+ LPAREN,
+ param,
+ RPAREN,
+ tc,
+ SEMI);
+ attachStuff(new JavaNode[] {#interfaceField, #mods, #t});
+ }
+ | v:variableDefinitions[#mods,#t] semi:SEMI!
+ {
+ #interfaceField = #v;
+
+ #interfaceField.addChild(#semi);
+
+ AST next = #interfaceField.getNextSibling();
+ // HACK for multiple variable declaration in one statement
+ // e.g float x, y, z;
+ // the semicolon will only be added to the first statement so
+ // we have to add it manually to all others
+ if (next != null)
+ {
+ AST ssemi = JavaNodeHelper.getFirstChild(#interfaceField, JavaTokenTypes.SEMI);
+
+ for (AST var = next; var != null; var = var.getNextSibling())
+ {
+ var.addChild(astFactory.create(ssemi));
+ }
+ }
+
+
+ }
+ )
+ )
+ ;
+
+constructorBody
+ : lc:LCURLY^ {#lc.setType(SLIST);}
+ ( options { greedy=true; } : explicitConstructorInvocation)?
+ (statement)*
+ RCURLY
+ ;
+
+/** Catch obvious constructor calls, but not the expr.super(...) calls */
+explicitConstructorInvocation
+ : (typeArguments)?
+ ( "this" lp1:LPAREN^ argList RPAREN SEMI
+ {#lp1.setType(CTOR_CALL);}
+ | "super" lp2:LPAREN^ argList RPAREN SEMI
+ {#lp2.setType(SUPER_CTOR_CALL);}
+ )
+ ;
+
+/** Catch variable definitions but add the semicolon ???*/
+typeVariableDefinitions[JavaNode mods, JavaNode t]
+ : v:variableDefinitions[mods,t]
+ (semi:SEMI
+ {
+ #v.addChild(#semi);
+ }
+ )
+ ;
+
+variableDefinitions[JavaNode mods, JavaNode t]
+ : variableDeclarator[(JavaNode)getASTFactory().dupTree(mods),
+ (JavaNode)getASTFactory().dupTree(t)]
+ ( COMMA!
+ variableDeclarator[(JavaNode)getASTFactory().dupTree(mods),
+ (JavaNode)getASTFactory().dupTree(t)]
+ )*
+
+ ;
+
+/** Declaration of a variable. This can be a class/instance variable,
+ * or a local variable in a method
+ * It can also include possible initialization.
+ */
+variableDeclarator![JavaNode mods, JavaNode t]
+ : id:IDENT d:declaratorBrackets[t] v:varInitializer
+ {#variableDeclarator = #(#[VARIABLE_DEF,"VARIABLE_DEF"], mods, #(#[TYPE,"TYPE"],d), id, v);
+ attachStuff(new JavaNode[] {#variableDeclarator,mods, t});
+ }
+ ;
+
+declaratorBrackets[JavaNode typ]
+ : {#declaratorBrackets=typ;}
+ (lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK!)*
+ ;
+
+varInitializer
+ : ( ASSIGN^ initializer )?
+ ;
+
+// This is an initializer used to set up an array.
+arrayInitializer
+ : lc:LCURLY^ {#lc.setType(ARRAY_INIT);}
+ ( initializer
+ (
+ // CONFLICT: does a COMMA after an initializer start a new
+ // initializer or start the option ',' at end?
+ // ANTLR generates proper code by matching
+ // the comma as soon as possible.
+ options {
+ warnWhenFollowAmbig = false;
+ }
+ :
+ COMMA initializer
+ )*
+ (COMMA)?
+ )?
+ RCURLY
+ ;
+
+
+// The two "things" that can initialize an array element are an expression
+// and another (nested) array initializer.
+initializer
+ : expression
+ | arrayInitializer
+ ;
+
+// This is the header of a method. It includes the name and parameters
+// for the method.
+// This also watches for a list of exception classes in a "throws" clause.
+ctorHead
+ : IDENT // the name of the method
+
+ // parse the formal parameter declarations.
+ LPAREN parameterDeclarationList RPAREN
+
+ // get the list of exceptions that this method is declared to throw
+ (throwsClause)?
+ ;
+
+// This is a list of exception classes that the method is declared to throw
+throwsClause
+ : "throws"^ identifier ( COMMA identifier )*
+ ;
+
+// A list of formal parameters
+// Zero or more parameters
+// If a parameter is variable length (e.g. String... myArg) it is the right-most parameter
+parameterDeclarationList
+ // The semantic check in ( .... )* block is flagged as superfluous, and seems superfluous but
+ // is the only way I could make this work. If my understanding is correct this is a known bug
+ : ( ( parameterDeclaration )=> parameterDeclaration
+ ( options {warnWhenFollowAmbig=false;} : ( COMMA parameterDeclaration ) => COMMA parameterDeclaration )*
+ ( COMMA variableLengthParameterDeclaration )?
+ |
+ variableLengthParameterDeclaration
+ )?
+ {#parameterDeclarationList = #(#[PARAMETERS,"PARAMETERS"],
+ #parameterDeclarationList);}
+ ;
+
+// A formal parameter.
+parameterDeclaration!
+ : pm:parameterModifier t:typeSpec[false] id:IDENT
+ pd:declaratorBrackets[#t]
+ {#parameterDeclaration = #(#[PARAMETER_DEF,"PARAMETER_DEF"],
+ pm, #([TYPE,"TYPE"],pd), id);}
+ ;
+
+variableLengthParameterDeclaration!
+ : pm:parameterModifier t:typeSpec[false] TRIPLE_DOT id:IDENT
+ pd:declaratorBrackets[#t]
+ {#variableLengthParameterDeclaration = #(#[VARIABLE_PARAMETER_DEF,"VARIABLE_PARAMETER_DEF"],
+ pm, #([TYPE,"TYPE"],pd), id);}
+ ;
+
+parameterModifier
+ //final can appear amongst annotations in any order - greedily consume any preceding
+ //annotations to shut nond-eterminism warnings off
+ : (options{greedy=true;} : annotation)* (f:"final")? (annotation)*
+ {#parameterModifier = #(#[MODIFIERS,"MODIFIERS"], #parameterModifier);}
+ ;
+
+// Compound statement. This is used in many contexts:
+// Inside a class definition prefixed with "static":
+// it is a class initializer
+// Inside a class definition without "static":
+// it is an instance initializer
+// As the body of a method
+// As a completely indepdent braced block of code inside a method
+// it starts a new scope for variable definitions
+
+compoundStatement
+ : lc:LCURLY^ {#lc.setType(SLIST);}
+ // include the (possibly-empty) list of statements
+ (statement)*
+ RCURLY
+ ;
+
+
+statement
+ // A list of statements in curly braces -- start a new scope!
+ : compoundStatement
+
+ // declarations are ambiguous with "ID DOT" relative to expression
+ // statements. Must backtrack to be sure. Could use a semantic
+ // predicate to test symbol table to see what the type was coming
+ // up, but that's pretty hard without a symbol table ;)
+ // (declaration)=> declaration SEMI
+ | (declaration)=> decl:declaration semi1:SEMI!
+ {
+ // add semicolon to the AST
+ #decl.addChild(#semi1);
+
+ AST next = currentAST.root.getNextSibling();
+
+ // HACK for multiple variable declaration in one statement
+ // e.g float x, y, z;
+ // the semicolon will only be added to the first statement so
+ // we have to add it manually to all others
+ if (next != null)
+ {
+ AST semi = JavaNodeHelper.getFirstChild(currentAST.root, JavaTokenTypes.SEMI);
+
+ for (AST var = next; var != null; var = var.getNextSibling())
+ {
+ var.addChild(astFactory.create(semi));
+ }
+ }
+ }
+
+ // An expression statement. This could be a method call,
+ // assignment statement, or any other expression evaluated for
+ // side-effects.
+ | e:expression semi2:SEMI!
+ {#e.addChild(#semi2);
+ }
+
+ //TODO: what abour interfaces, enums and annotations
+ // class definition
+ | m:modifiers! classDefinition[#m]
+
+ // Attach a label to the front of a statement
+ | IDENT c:COLON^ {#c.setType(LABELED_STAT);} statement
+
+ // If-else statement
+ | "if"^ LPAREN expression RPAREN statement
+ (
+ // CONFLICT: the old "dangling-else" problem...
+ // ANTLR generates proper code matching
+ // as soon as possible. Hush warning.
+ options {
+ warnWhenFollowAmbig = false;
+ }
+ :
+ "else" statement
+ )?
+
+ // For statement
+ | forStatement
+
+ // While statement
+ | "while"^ LPAREN expression RPAREN statement
+
+ // do-while statement
+ | "do"^ statement "while" LPAREN expression RPAREN SEMI
+
+ // get out of a loop (or switch)
+ | "break"^ (IDENT)? SEMI
+
+ // do next iteration of a loop
+ | "continue"^ (IDENT)? SEMI
+
+ // Return an expression
+ | "return"^ (expression)? SEMI
+
+ // switch/case statement
+ | "switch"^ LPAREN expression RPAREN LCURLY
+ ( casesGroup )*
+ RCURLY
+
+ // exception try-catch block
+ | tryBlock
+
+ // throw an exception
+ | "throw"^ expression SEMI
+
+ // synchronize a statement
+ | synBlock:"synchronized"^ LPAREN expression RPAREN compoundStatement
+ { #synBlock.setType(SYNBLOCK);}
+
+ // asserts (uncomment if you want 1.4 compatibility)
+ | "assert"^ expression ( COLON! expression )? SEMI
+
+ // empty statement possibly ?????
+ | s:SEMI {#s.setType(EMPTY_STAT);}
+ ;
+
+forStatement
+ : f:"for"^
+ LPAREN
+ ( (forInit SEMI)=>traditionalForClause
+ | forEachClause
+ )
+ RPAREN
+ statement // statement to loop over
+ ;
+
+traditionalForClause
+ :
+ forInit SEMI // initializer
+ forCond SEMI // condition test
+ forIter // updater
+ ;
+
+forEachClause
+ :
+ p:parameterDeclaration COLON! expression
+ {#forEachClause = #(#[FOR_EACH_CLAUSE,"FOR_EACH_CLAUSE"], #forEachClause);}
+ ;
+
+casesGroup
+ : ( // CONFLICT: to which case group do the statements bind?
+ // ANTLR generates proper code: it groups the
+ // many "case"/"default" labels together then
+ // follows them with the statements
+ options {
+ greedy = true;
+ }
+ :
+ aCase
+ )+
+ caseSList
+ {#casesGroup = #([CASE_GROUP, "CASE_GROUP"], #casesGroup);}
+ ;
+
+aCase
+ : ("case"^ expression | "default") COLON
+ ;
+
+caseSList
+ : (statement)*
+ {#caseSList = #(#[CASESLIST,"CASESLIST"],#caseSList);}
+ ;
+
+// The initializer for a for loop
+forInit
+ // if it looks like a declaration, it is
+ : ((declaration)=> declaration
+ // otherwise it could be an expression list...
+ | expressionList
+ )?
+ {#forInit = #(#[FOR_INIT,"FOR_INIT"],#forInit);}
+ ;
+
+forCond
+ : (expression)?
+ {#forCond = #(#[FOR_CONDITION,"FOR_CONDITION"],#forCond);}
+ ;
+
+forIter
+ : (expressionList)?
+ {#forIter = #(#[FOR_ITERATOR,"FOR_ITERATOR"],#forIter);}
+ ;
+
+// an exception handler try/catch block
+tryBlock
+ : "try"^ compoundStatement
+ (handler)*
+ ( finallyClause )?
+ ;
+
+finallyClause
+ : "finally"^ compoundStatement
+ ;
+
+// an exception handler
+handler
+ : "catch"^ LPAREN parameterDeclaration RPAREN compoundStatement
+ ;
+
+
+// expressions
+// Note that most of these expressions follow the pattern
+// thisLevelExpression :
+// nextHigherPrecedenceExpression
+// (OPERATOR nextHigherPrecedenceExpression)*
+// which is a standard recursive definition for a parsing an expression.
+// The operators in java have the following precedences:
+// lowest (13) = *= /= %= += -= <<= >>= >>>= &= ^= |=
+// (12) ?:
+// (11) ||
+// (10) &&
+// ( 9) |
+// ( 8) ^
+// ( 7) &
+// ( 6) == !=
+// ( 5) < <= > >=
+// ( 4) << >>
+// ( 3) +(binary) -(binary)
+// ( 2) * / %
+// ( 1) ++ -- +(unary) -(unary) ~ ! (type)
+// [] () (method call) . (dot -- identifier qualification)
+// new () (explicit parenthesis)
+//
+// the last two are not usually on a precedence chart; I put them in
+// to point out that new has a higher precedence than '.', so you
+// can validy use
+// new Frame().show()
+//
+// Note that the above precedence levels map to the rules below...
+// Once you have a precedence chart, writing the appropriate rules as below
+// is usually very straightfoward
+
+
+
+// the mother of all expressions
+expression
+ : assignmentExpression
+ {#expression = #(#[EXPR,"EXPR"],#expression);}
+ ;
+
+
+// This is a list of expressions.
+expressionList
+ : expression (COMMA expression)*
+ {#expressionList = #(#[ELIST,"ELIST"], expressionList);}
+ ;
+
+
+// assignment expression (level 13)
+assignmentExpression
+ : conditionalExpression
+ ( ( ASSIGN^
+ | PLUS_ASSIGN^
+ | MINUS_ASSIGN^
+ | STAR_ASSIGN^
+ | DIV_ASSIGN^
+ | MOD_ASSIGN^
+ | SR_ASSIGN^
+ | BSR_ASSIGN^
+ | SL_ASSIGN^
+ | BAND_ASSIGN^
+ | BXOR_ASSIGN^
+ | BOR_ASSIGN^
+ )
+ assignmentExpression
+ )?
+ ;
+
+
+// conditional test (level 12)
+conditionalExpression
+ : logicalOrExpression
+ ( QUESTION^ assignmentExpression COLON conditionalExpression )?
+ ;
+
+
+// logical or (||) (level 11)
+logicalOrExpression
+ : logicalAndExpression (LOR^ logicalAndExpression)*
+ ;
+
+
+// logical and (&&) (level 10)
+logicalAndExpression
+ : inclusiveOrExpression (LAND^ inclusiveOrExpression)*
+ ;
+
+
+// bitwise or non-short-circuiting or (|) (level 9)
+inclusiveOrExpression
+ : exclusiveOrExpression (BOR^ exclusiveOrExpression)*
+ ;
+
+
+// exclusive or (^) (level 8)
+exclusiveOrExpression
+ : andExpression (BXOR^ andExpression)*
+ ;
+
+
+// bitwise or non-short-circuiting and (&) (level 7)
+andExpression
+ : equalityExpression (BAND^ equalityExpression)*
+ ;
+
+
+// equality/inequality (==/!=) (level 6)
+equalityExpression
+ : relationalExpression ((NOT_EQUAL^ | EQUAL^) relationalExpression)*
+ ;
+
+
+// boolean relational expressions (level 5)
+relationalExpression
+ : shiftExpression
+ ( ( ( LT^
+ | GT^
+ | LE^
+ | GE^
+ )
+ shiftExpression
+ )*
+ | "instanceof"^ typeSpec[true]
+ )
+ ;
+
+
+// bit shift expressions (level 4)
+shiftExpression
+ : additiveExpression ((SL^ | SR^ | BSR^) additiveExpression)*
+ ;
+
+
+// binary addition/subtraction (level 3)
+additiveExpression
+ : multiplicativeExpression ((PLUS^ | MINUS^) multiplicativeExpression)*
+ ;
+
+
+// multiplication/division/modulo (level 2)
+multiplicativeExpression
+ : unaryExpression ((STAR^ | DIV^ | MOD^ ) unaryExpression)*
+ ;
+
+unaryExpression
+ : INC^ unaryExpression
+ | DEC^ unaryExpression
+ | MINUS^ {#MINUS.setType(UNARY_MINUS);} unaryExpression
+ | PLUS^ {#PLUS.setType(UNARY_PLUS);} unaryExpression
+ | unaryExpressionNotPlusMinus
+ ;
+
+unaryExpressionNotPlusMinus
+ : BNOT^ unaryExpression
+ | LNOT^ unaryExpression
+ | ( // subrule allows option to shut off warnings
+ options {
+ // "(int" ambig with postfixExpr due to lack of sequence
+ // info in linear approximate LL(k). It's ok. Shut up.
+ generateAmbigWarnings=false;
+ }
+ : // If typecast is built in type, must be numeric operand
+ // Have to backtrack to see if operator follows
+ (LPAREN builtInTypeSpec[true] RPAREN unaryExpression)=>
+ lpb:LPAREN^ {#lpb.setType(TYPECAST);} builtInTypeSpec[true] RPAREN!
+ unaryExpression
+
+ // Have to backtrack to see if operator follows. If no operator
+ // follows, it's a typecast. No semantic checking needed to parse.
+ // if it _looks_ like a cast, it _is_ a cast; else it's a "(expr)"
+ | (LPAREN classTypeSpec[true] RPAREN unaryExpressionNotPlusMinus)=>
+ lp:LPAREN^ {#lp.setType(TYPECAST);} classTypeSpec[true] RPAREN!
+ unaryExpressionNotPlusMinus
+
+ | postfixExpression
+ )
+ ;
+
+// qualified names, array expressions, method invocation, post inc/dec
+postfixExpression
+ :
+ primaryExpression
+
+ (
+ /*
+ options {
+ // the use of postfixExpression in SUPER_CTOR_CALL adds DOT
+ // to the lookahead set, and gives loads of false non-det
+ // warnings.
+ // shut them off.
+ generateAmbigWarnings=false;
+ }
+ : */
+ //type arguments are only appropriate for a parameterized method/ctor invocations
+ //semantic check may be needed here to ensure that this is the case
+ DOT^ (typeArguments)?
+ ( IDENT
+ ( lp:LPAREN^ {#lp.setType(METHOD_CALL);}
+ argList
+ RPAREN
+ )?
+ | "super"
+ ( // (new Outer()).super() (create enclosing instance)
+ lp3:LPAREN^ argList RPAREN
+ {#lp3.setType(SUPER_CTOR_CALL);}
+ | DOT^ (typeArguments)? IDENT
+ ( lps:LPAREN^ {#lps.setType(METHOD_CALL);}
+ argList
+ RPAREN
+ )?
+ )
+ )
+ | DOT^ "this"
+ | DOT^ newExpression
+ | lb:LBRACK^ {#lb.setType(INDEX_OP);} expression RBRACK
+ )*
+
+ ( // possibly add on a post-increment or post-decrement.
+ // allows INC/DEC on too much, but semantics can check
+ in:INC^ {#in.setType(POST_INC);}
+ | de:DEC^ {#de.setType(POST_DEC);}
+ )?
+ ;
+
+// the basic element of an expression
+primaryExpression
+ : identPrimary ( options {greedy=true;} : DOT^ "class" )?
+ | constant
+ | "true"
+ | "false"
+ | "null"
+ | newExpression
+ | "this"
+ | "super"
+ | LPAREN assignmentExpression RPAREN
+ // look for int.class and int[].class
+ | builtInType
+ ( lbt:LBRACK^ {#lbt.setType(ARRAY_DECLARATOR);} RBRACK! )*
+ DOT^ "class"
+ ;
+
+/** Match a, a.b.c refs, a.b.c(...) refs, a.b.c[], a.b.c[].class,
+ * and a.b.c.class refs. Also this(...) and super(...). Match
+ * this or super.
+ */
+identPrimary
+ : (ta1:typeArguments!)?
+ IDENT
+ // Syntax for method invocation with type arguments is
+ // foo("blah")
+ (
+ options {
+ // .ident could match here or in postfixExpression.
+ // We do want to match here. Turn off warning.
+ greedy=true;
+ // This turns the ambiguity warning of the second alternative
+ // off. See below. (The "false" predicate makes it non-issue)
+ warnWhenFollowAmbig=false;
+ }
+ // we have a new nondeterminism because of
+ // typeArguments... only a syntactic predicate will help...
+ // The problem is that this loop here conflicts with
+ // DOT typeArguments "super" in postfixExpression (k=2)
+ // A proper solution would require a lot of refactoring...
+// Original way.
+// : (DOT (typeArguments)? IDENT) =>
+// DOT^ (ta2:typeArguments!)? IDENT
+ : (DOT^ (typeArguments)? IDENT)
+ | {false}? // FIXME: this is very ugly but it seems to work...
+ // this will also produce an ANTLR warning!
+ // Unfortunately a syntactic predicate can only select one of
+ // multiple alternatives on the same level, not break out of
+ // an enclosing loop, which is why this ugly hack (a fake
+ // empty alternative with always-false semantic predicate)
+ // is necessary.
+ )*
+ (
+ options {
+ // ARRAY_DECLARATOR here conflicts with INDEX_OP in
+ // postfixExpression on LBRACK RBRACK.
+ // We want to match [] here, so greedy. This overcomes
+ // limitation of linear approximate lookahead.
+ greedy=true;
+ }
+ : ( lp:LPAREN^ {#lp.setType(METHOD_CALL);}
+ // if the input is valid, only the last IDENT may
+ // have preceding typeArguments... rather hacky, this is...
+// Not required because see above
+// {if (#ta2 != null) astFactory.addASTChild(currentAST, #ta2);}
+// {if (#ta2 == null) astFactory.addASTChild(currentAST, #ta1);}
+ argList RPAREN
+ )
+ | ( options {greedy=true;} :
+ lbc:LBRACK^ {#lbc.setType(ARRAY_DECLARATOR);} RBRACK!
+ )+
+ )?
+ ;
+
+/** object instantiation.
+ * Trees are built as illustrated by the following input/tree pairs:
+ *
+ * new T()
+ *
+ * new
+ * |
+ * T -- ELIST
+ * |
+ * arg1 -- arg2 -- .. -- argn
+ *
+ * new int[]
+ *
+ * new
+ * |
+ * int -- ARRAY_DECLARATOR
+ *
+ * new int[] {1,2}
+ *
+ * new
+ * |
+ * int -- ARRAY_DECLARATOR -- ARRAY_INIT
+ * |
+ * EXPR -- EXPR
+ * | |
+ * 1 2
+ *
+ * new int[3]
+ * new
+ * |
+ * int -- ARRAY_DECLARATOR
+ * |
+ * EXPR
+ * |
+ * 3
+ *
+ * new int[1][2]
+ *
+ * new
+ * |
+ * int -- ARRAY_DECLARATOR
+ * |
+ * ARRAY_DECLARATOR -- EXPR
+ * | |
+ * EXPR 1
+ * |
+ * 2
+ *
+ */
+newExpression
+ : "new"^ (typeArguments)? type
+ ( LPAREN argList RPAREN (classBlock)?
+
+ //java 1.1
+ // Note: This will allow bad constructs like
+ // new int[4][][3] {exp,exp}.
+ // There needs to be a semantic check here...
+ // to make sure:
+ // a) [ expr ] and [ ] are not mixed
+ // b) [ expr ] and an init are not used together
+
+ | newArrayDeclarator (arrayInitializer)?
+ )
+ ;
+
+argList
+ : ( expressionList
+ | /*nothing*/
+ {#argList = #[ELIST,"ELIST"];}
+ )
+ ;
+
+newArrayDeclarator
+ : (
+ // CONFLICT:
+ // newExpression is a primaryExpression which can be
+ // followed by an array index reference. This is ok,
+ // as the generated code will stay in this loop as
+ // long as it sees an LBRACK (proper behavior)
+ options {
+ warnWhenFollowAmbig = false;
+ }
+ :
+ lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);}
+ (expression)?
+ RBRACK!
+ )+
+ ;
+
+constant
+ : NUM_INT
+ | CHAR_LITERAL
+ | STRING_LITERAL
+ | NUM_FLOAT
+ | NUM_LONG
+ | NUM_DOUBLE
+ ;
+
+
+//----------------------------------------------------------------------------
+// The Java scanner
+//----------------------------------------------------------------------------
+class InternalJavaLexer extends Lexer;
+
+options {
+ exportVocab=Java; // call the vocabulary "Java"
+ testLiterals=false; // don't automatically test for literals
+ k=4; // four characters of lookahead
+ charVocabulary='\u0003'..'\uFFFF';
+ // without inlining some bitset tests, couldn't do unicode;
+ // I need to make ANTLR generate smaller bitsets; see
+ // bottom of JavaLexer.java
+ codeGenBitsetTestThreshold=20;
+ // This class is abstract
+ classHeaderPrefix = "public abstract";
+}
+
+{
+ /** flag for enabling the "assert" keyword */
+ private boolean assertEnabled = true;
+ /** flag for enabling the "enum" keyword */
+ private boolean enumEnabled = true;
+
+ /** Enable the "assert" keyword */
+ public void enableAssert(boolean shouldEnable) { assertEnabled = shouldEnable; }
+ /** Query the "assert" keyword state */
+ public boolean isAssertEnabled() { return assertEnabled; }
+ /** Enable the "enum" keyword */
+ public void enableEnum(boolean shouldEnable) { enumEnabled = shouldEnable; }
+ /** Query the "enum" keyword state */
+ public boolean isEnumEnabled() { return enumEnabled; }
+
+ protected abstract Token makeJavaDoc(Token node, String text) throws TokenStreamIOException;
+
+}
+
+// OPERATORS
+QUESTION : '?' ;
+LPAREN : '(' ;
+RPAREN : ')' ;
+LBRACK : '[' ;
+RBRACK : ']' ;
+LCURLY : '{' ;
+RCURLY : '}' ;
+COLON : ':' ;
+COMMA : ',' ;
+//DOT : '.' ;
+ASSIGN : '=' ;
+EQUAL : "==" ;
+LNOT : '!' ;
+BNOT : '~' ;
+NOT_EQUAL : "!=" ;
+DIV : '/' ;
+DIV_ASSIGN : "/=" ;
+PLUS : '+' ;
+PLUS_ASSIGN : "+=" ;
+INC : "++" ;
+MINUS : '-' ;
+MINUS_ASSIGN : "-=" ;
+DEC : "--" ;
+STAR : '*' ;
+STAR_ASSIGN : "*=" ;
+MOD : '%' ;
+MOD_ASSIGN : "%=" ;
+SR : ">>" ;
+SR_ASSIGN : ">>=" ;
+BSR : ">>>" ;
+BSR_ASSIGN : ">>>=" ;
+GE : ">=" ;
+GT : ">" ;
+SL : "<<" ;
+SL_ASSIGN : "<<=" ;
+LE : "<=" ;
+LT : '<' ;
+BXOR : '^' ;
+BXOR_ASSIGN : "^=" ;
+BOR : '|' ;
+BOR_ASSIGN : "|=" ;
+LOR : "||" ;
+BAND : '&' ;
+BAND_ASSIGN : "&=" ;
+LAND : "&&" ;
+SEMI : ';' ;
+
+
+// Whitespace -- ignored
+WS : ( ' '
+ | '\t'
+ | '\f'
+ // handle newlines
+ | ( options {generateAmbigWarnings=false;}
+ : "\r\n" // Evil DOS
+ | '\r' // Macintosh
+ | '\n' // Unix (the right way)
+ )
+ { newline(); }
+ )+
+ { // _ttype = Token.SKIP;
+ }
+ ;
+
+protected SEPARATOR_COMMENT
+: "//~" (~('\n'|'\r') {if (LA(1) == EOF_CHAR) break;} )*
+ ( '\n'! | '\r'!('\n'!)? )?
+ {newline();}
+;
+
+// Single-line comments
+protected SL_COMMENT
+: "//" (~('\n'|'\r') {if (LA(1) == EOF_CHAR) break;} )*
+ ( '\n'! | '\r'!('\n'!)? )?
+ {newline();
+
+ }
+;
+COMMENT
+:
+ (
+ options {
+ // ANTLR does it right by consuming input as soon as possible
+ generateAmbigWarnings=false;
+ // TODO spec:SPECIAL_COMMENT {$setToken(spec);} |
+ }:
+
+ sep:SEPARATOR_COMMENT {$setToken(sep); } |
+ sl:SL_COMMENT {$setToken(sl); }
+ )
+;
+
+// multiple-line comments
+ML_COMMENT
+ : "/*"
+ ( /* '\r' '\n' can be matched in one alternative or by matching
+ '\r' in one iteration and '\n' in another. I am trying to
+ handle any flavor of newline that comes in, but the language
+ that allows both "\r\n" and "\r" and "\n" to all be valid
+ newline is ambiguous. Consequently, the resulting grammar
+ must be ambiguous. I'm shutting this warning off.
+ */
+ options {
+ generateAmbigWarnings=false;
+ }
+ :
+ { LA(2)!='/' }? '*'
+ | '\r' '\n' {newline();}
+ | '\r' {newline();}
+ | '\n' {newline();}
+ | ~('*'|'\n'|'\r')
+ )*
+ "*/"
+ {
+ // $setType(Token.SKIP);
+ Token n = makeJavaDoc(makeToken(_ttype), $getText);
+ $setToken(n);
+ $setType(n.getType());
+ }
+ ;
+
+
+// character literals
+CHAR_LITERAL
+ : '\'' ( ESC | ~('\''|'\n'|'\r'|'\\') ) '\''
+ ;
+
+// string literals
+STRING_LITERAL
+ : '"' (ESC|~('"'|'\\'|'\n'|'\r'))* '"'
+ ;
+
+
+// escape sequence -- note that this is protected; it can only be called
+// from another lexer rule -- it will not ever directly return a token to
+// the parser
+// There are various ambiguities hushed in this rule. The optional
+// '0'...'9' digit matches should be matched here rather than letting
+// them go back to STRING_LITERAL to be matched. ANTLR does the
+// right thing by matching immediately; hence, it's ok to shut off
+// the FOLLOW ambig warnings.
+protected
+ESC
+ : '\\'
+ ( 'n'
+ | 'r'
+ | 't'
+ | 'b'
+ | 'f'
+ | '"'
+ | '\''
+ | '\\'
+ | ('u')+ HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
+ | '0'..'3'
+ (
+ options {
+ warnWhenFollowAmbig = false;
+ }
+ : '0'..'7'
+ (
+ options {
+ warnWhenFollowAmbig = false;
+ }
+ : '0'..'7'
+ )?
+ )?
+ | '4'..'7'
+ (
+ options {
+ warnWhenFollowAmbig = false;
+ }
+ : '0'..'7'
+ )?
+ )
+ ;
+
+
+// hexadecimal digit (again, note it's protected!)
+protected
+HEX_DIGIT
+ : ('0'..'9'|'A'..'F'|'a'..'f')
+ ;
+
+
+// a dummy rule to force vocabulary to be all characters (except special
+// ones that ANTLR uses internally (0 to 2)
+protected
+VOCAB
+ : '\3'..'\377'
+ ;
+
+
+// an identifier. Note that testLiterals is set to true! This means
+// that after we match the rule, we look in the literals table to see
+// if it's a literal or really an identifer
+IDENT
+ options {testLiterals=true;}
+ : ('a'..'z'|'A'..'Z'|'_'|'$') ('a'..'z'|'A'..'Z'|'_'|'0'..'9'|'$')*
+ {
+ // check if "assert" keyword is enabled
+ if (assertEnabled && "assert".equals($getText)) {
+ $setType(LITERAL_assert); // set token type for the rule in the parser
+ }
+ // check if "enum" keyword is enabled
+ if (enumEnabled && "enum".equals($getText)) {
+ $setType(LITERAL_enum); // set token type for the rule in the parser
+ }
+ }
+ ;
+
+
+// a numeric literal
+NUM_INT
+ {boolean isDecimal=false; Token t=null;}
+ : '.' {_ttype = DOT;}
+ (
+ (('0'..'9')+ (EXPONENT)? (f1:FLOAT_SUFFIX {t=f1;})?
+ {
+ if (t != null && t.getText().toUpperCase().indexOf('F')>=0) {
+ _ttype = NUM_FLOAT;
+ }
+ else {
+ _ttype = NUM_DOUBLE; // assume double
+ }
+ })
+ |
+ // JDK 1.5 token for variable length arguments
+ (".." {_ttype = TRIPLE_DOT;})
+ )?
+
+ | ( '0' {isDecimal = true;} // special case for just '0'
+ ( ('x'|'X')
+ ( // hex
+ // the 'e'|'E' and float suffix stuff look
+ // like hex digits, hence the (...)+ doesn't
+ // know when to stop: ambig. ANTLR resolves
+ // it correctly by matching immediately. It
+ // is therefor ok to hush warning.
+ options {
+ warnWhenFollowAmbig=false;
+ }
+ : HEX_DIGIT
+ )+
+
+ | //float or double with leading zero
+ (('0'..'9')+ ('.'|EXPONENT|FLOAT_SUFFIX)) => ('0'..'9')+
+
+ | ('0'..'7')+ // octal
+ )?
+ | ('1'..'9') ('0'..'9')* {isDecimal=true;} // non-zero decimal
+ )
+ ( ('l'|'L') { _ttype = NUM_LONG; }
+
+ // only check to see if it's a float if looks like decimal so far
+ | {isDecimal}?
+ ( '.' ('0'..'9')* (EXPONENT)? (f2:FLOAT_SUFFIX {t=f2;})?
+ | EXPONENT (f3:FLOAT_SUFFIX {t=f3;})?
+ | f4:FLOAT_SUFFIX {t=f4;}
+ )
+ {
+ if (t != null && t.getText().toUpperCase() .indexOf('F') >= 0) {
+ _ttype = NUM_FLOAT;
+ }
+ else {
+ _ttype = NUM_DOUBLE; // assume double
+ }
+ }
+ )?
+ ;
+
+// JDK 1.5 token for annotations and their declarations
+AT
+ : '@'
+ ;
+
+// a couple protected methods to assist in matching floating point numbers
+protected
+EXPONENT
+ : ('e'|'E') ('+'|'-')? ('0'..'9')+
+ ;
+
+
+protected
+FLOAT_SUFFIX
+ : 'f'|'F'|'d'|'D'
+ ;
+
diff --git a/app/src/antlr/java/java.tree.g b/app/src/antlr/java/java.tree.g
new file mode 100644
index 000000000..e995ef49d
--- /dev/null
+++ b/app/src/antlr/java/java.tree.g
@@ -0,0 +1,326 @@
+package antlr;
+
+
+/** Java 1.3 AST Recognizer Grammar
+ *
+ * Author: (see java.g preamble)
+ *
+ * This grammar is in the PUBLIC DOMAIN
+ */
+class JavaTreeParser extends TreeParser;
+
+options {
+ importVocab = Java;
+}
+
+compilationUnit
+ : (packageDefinition)?
+ (importDefinition)*
+ (typeDefinition)*
+ ;
+
+packageDefinition
+ : #( PACKAGE_DEF identifier )
+ ;
+
+importDefinition
+ : #( IMPORT identifierStar )
+ ;
+
+typeDefinition
+ : #(CLASS_DEF modifiers IDENT extendsClause implementsClause objBlock )
+ | #(INTERFACE_DEF modifiers IDENT extendsClause interfaceBlock )
+ ;
+
+typeSpec
+ : #(TYPE typeSpecArray)
+ ;
+
+typeSpecArray
+ : #( ARRAY_DECLARATOR typeSpecArray )
+ | type
+ ;
+
+type: identifier
+ | builtInType
+ ;
+
+builtInType
+ : "void"
+ | "boolean"
+ | "byte"
+ | "char"
+ | "short"
+ | "int"
+ | "float"
+ | "long"
+ | "double"
+ ;
+
+modifiers
+ : #( MODIFIERS (modifier)* )
+ ;
+
+modifier
+ : "private"
+ | "public"
+ | "protected"
+ | "static"
+ | "transient"
+ | "final"
+ | "abstract"
+ | "native"
+ | "threadsafe"
+ | "synchronized"
+ | "const"
+ | "volatile"
+ | "strictfp"
+ ;
+
+extendsClause
+ : #(EXTENDS_CLAUSE (identifier)* )
+ ;
+
+implementsClause
+ : #(IMPLEMENTS_CLAUSE (identifier)* )
+ ;
+
+
+interfaceBlock
+ : #( OBJBLOCK
+ ( methodDecl
+ | variableDef
+ )*
+ )
+ ;
+
+objBlock
+ : #( OBJBLOCK
+ ( ctorDef
+ | methodDef
+ | variableDef
+ | typeDefinition
+ | #(STATIC_INIT slist)
+ | #(INSTANCE_INIT slist)
+ )*
+ )
+ ;
+
+ctorDef
+ : #(CTOR_DEF modifiers methodHead (slist)?)
+ ;
+
+methodDecl
+ : #(METHOD_DEF modifiers typeSpec methodHead)
+ ;
+
+methodDef
+ : #(METHOD_DEF modifiers typeSpec methodHead (slist)?)
+ ;
+
+variableDef
+ : #(VARIABLE_DEF modifiers typeSpec variableDeclarator varInitializer)
+ ;
+
+parameterDef
+ : #(PARAMETER_DEF modifiers typeSpec IDENT )
+ ;
+
+objectinitializer
+ : #(INSTANCE_INIT slist)
+ ;
+
+variableDeclarator
+ : IDENT
+ | LBRACK variableDeclarator
+ ;
+
+varInitializer
+ : #(ASSIGN initializer)
+ |
+ ;
+
+initializer
+ : expression
+ | arrayInitializer
+ ;
+
+arrayInitializer
+ : #(ARRAY_INIT (initializer)*)
+ ;
+
+methodHead
+ : IDENT #( PARAMETERS (parameterDef)* ) (throwsClause)?
+ ;
+
+throwsClause
+ : #( "throws" (identifier)* )
+ ;
+
+identifier
+ : IDENT
+ | #( DOT identifier IDENT )
+ ;
+
+identifierStar
+ : IDENT
+ | #( DOT identifier (STAR|IDENT) )
+ ;
+
+slist
+ : #( SLIST (stat)* )
+ ;
+
+stat: typeDefinition
+ | variableDef
+ | expression
+ | #(LABELED_STAT IDENT stat)
+ | #("if" expression stat (stat)? )
+ | #( "for"
+ #(FOR_INIT (variableDef | elist)?)
+ #(FOR_CONDITION (expression)?)
+ #(FOR_ITERATOR (elist)?)
+ stat
+ )
+ | #("while" expression stat)
+ | #("do" stat expression)
+ | #("break" (IDENT)? )
+ | #("continue" (IDENT)? )
+ | #("return" (expression)? )
+ | #("switch" expression (caseGroup)*)
+ | #("throw" expression)
+ | #("synchronized" expression stat)
+ | tryBlock
+ | slist // nested SLIST
+ // uncomment to make assert JDK 1.4 stuff work
+ | #("assert" expression (expression)?)
+ | EMPTY_STAT
+ ;
+
+caseGroup
+ : #(CASE_GROUP (#("case" expression) | "default")+ slist)
+ ;
+
+tryBlock
+ : #( "try" slist (handler)* (#("finally" slist))? )
+ ;
+
+handler
+ : #( "catch" parameterDef slist )
+ ;
+
+elist
+ : #( ELIST (expression)* )
+ ;
+
+expression
+ : #(EXPR expr)
+ ;
+
+expr: #(QUESTION expr expr expr) // trinary operator
+ | #(ASSIGN expr expr) // binary operators...
+ | #(PLUS_ASSIGN expr expr)
+ | #(MINUS_ASSIGN expr expr)
+ | #(STAR_ASSIGN expr expr)
+ | #(DIV_ASSIGN expr expr)
+ | #(MOD_ASSIGN expr expr)
+ | #(SR_ASSIGN expr expr)
+ | #(BSR_ASSIGN expr expr)
+ | #(SL_ASSIGN expr expr)
+ | #(BAND_ASSIGN expr expr)
+ | #(BXOR_ASSIGN expr expr)
+ | #(BOR_ASSIGN expr expr)
+ | #(LOR expr expr)
+ | #(LAND expr expr)
+ | #(BOR expr expr)
+ | #(BXOR expr expr)
+ | #(BAND expr expr)
+ | #(NOT_EQUAL expr expr)
+ | #(EQUAL expr expr)
+ | #(LT expr expr)
+ | #(GT expr expr)
+ | #(LE expr expr)
+ | #(GE expr expr)
+ | #(SL expr expr)
+ | #(SR expr expr)
+ | #(BSR expr expr)
+ | #(PLUS expr expr)
+ | #(MINUS expr expr)
+ | #(DIV expr expr)
+ | #(MOD expr expr)
+ | #(STAR expr expr)
+ | #(INC expr)
+ | #(DEC expr)
+ | #(POST_INC expr)
+ | #(POST_DEC expr)
+ | #(BNOT expr)
+ | #(LNOT expr)
+ | #("instanceof" expr expr)
+ | #(UNARY_MINUS expr)
+ | #(UNARY_PLUS expr)
+ | primaryExpression
+ ;
+
+primaryExpression
+ : IDENT
+ | #( DOT
+ ( expr
+ ( IDENT
+ | arrayIndex
+ | "this"
+ | "class"
+ | #( "new" IDENT elist )
+ | "super"
+ )
+ | #(ARRAY_DECLARATOR typeSpecArray)
+ | builtInType ("class")?
+ )
+ )
+ | arrayIndex
+ | #(METHOD_CALL primaryExpression elist)
+ | ctorCall
+ | #(TYPECAST typeSpec expr)
+ | newExpression
+ | constant
+ | "super"
+ | "true"
+ | "false"
+ | "this"
+ | "null"
+ | typeSpec // type name used with instanceof
+ ;
+
+ctorCall
+ : #( CTOR_CALL elist )
+ | #( SUPER_CTOR_CALL
+ ( elist
+ | primaryExpression elist
+ )
+ )
+ ;
+
+arrayIndex
+ : #(INDEX_OP expr expression)
+ ;
+
+constant
+ : NUM_INT
+ | CHAR_LITERAL
+ | STRING_LITERAL
+ | NUM_FLOAT
+ | NUM_DOUBLE
+ | NUM_LONG
+ ;
+
+newExpression
+ : #( "new" type
+ ( newArrayDeclarator (arrayInitializer)?
+ | elist (objBlock)?
+ )
+ )
+
+ ;
+
+newArrayDeclarator
+ : #( ARRAY_DECLARATOR (newArrayDeclarator)? (expression)? )
+ ;
diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java
new file mode 100644
index 000000000..2a70cd6d6
--- /dev/null
+++ b/app/src/processing/app/Base.java
@@ -0,0 +1,2021 @@
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+/*
+ Part of the Processing project - http://processing.org
+
+ Copyright (c) 2004-08 Ben Fry and Casey Reas
+ Copyright (c) 2001-04 Massachusetts Institute of Technology
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+package processing.app;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.util.*;
+
+import javax.swing.*;
+
+import processing.app.debug.Compiler;
+import processing.core.*;
+
+
+/**
+ * The base class for the main processing application.
+ * Primary role of this class is for platform identification and
+ * general interaction with the system (launching URLs, loading
+ * files and images, etc) that comes from that.
+ */
+public class Base {
+ static final int REVISION = 165;
+ static String VERSION_NAME = "0165";
+
+ static HashMap platformNames = new HashMap();
+ static {
+ platformNames.put(PConstants.WINDOWS, "windows");
+ platformNames.put(PConstants.MACOSX, "macosx");
+ platformNames.put(PConstants.LINUX, "linux");
+ }
+
+ static HashMap platformIndices = new HashMap();
+ static {
+ platformIndices.put("windows", PConstants.WINDOWS);
+ platformIndices.put("macosx", PConstants.MACOSX);
+ platformIndices.put("linux", PConstants.LINUX);
+ }
+ static Platform platform;
+
+ static private boolean commandLine;
+
+ // A single instance of the preferences window
+ Preferences preferencesFrame;
+
+ // set to true after the first time the menu is built.
+ // so that the errors while building don't show up again.
+ boolean builtOnce;
+
+ static File buildFolder;
+
+ // these are static because they're used by Sketch
+ static private File examplesFolder;
+ static private File librariesFolder;
+ static private File toolsFolder;
+
+ // maps imported packages to their library folder
+ static HashMap importToLibraryTable;
+
+ // classpath for all known libraries for p5
+ // (both those in the p5/libs folder and those with lib subfolders
+ // found in the sketchbook)
+ static public String librariesClassPath;
+
+ // Location for untitled items
+ static File untitledFolder;
+
+ // p5 icon for the window
+ static Image icon;
+
+// int editorCount;
+// Editor[] editors;
+ java.util.List editors =
+ Collections.synchronizedList(new ArrayList());
+// ArrayList editors = Collections.synchronizedList(new ArrayList());
+ Editor activeEditor;
+
+// int nextEditorX;
+// int nextEditorY;
+
+
+ static public void main(String args[]) {
+ try {
+ File versionFile = getContentFile("lib/version.txt");
+ if (versionFile.exists()) {
+ VERSION_NAME = PApplet.loadStrings(versionFile)[0];
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+// if (System.getProperty("mrj.version") != null) {
+// //String jv = System.getProperty("java.version");
+// String ov = System.getProperty("os.version");
+// if (ov.startsWith("10.5")) {
+// System.setProperty("apple.laf.useScreenMenuBar", "true");
+// }
+// }
+
+ /*
+ commandLine = false;
+ if (args.length >= 2) {
+ if (args[0].startsWith("--")) {
+ commandLine = true;
+ }
+ }
+
+ if (PApplet.javaVersion < 1.5f) {
+ //System.err.println("no way man");
+ Base.showError("Need to install Java 1.5",
+ "This version of Processing requires \n" +
+ "Java 1.5 or later to run properly.\n" +
+ "Please visit java.com to upgrade.", null);
+ }
+ */
+
+ initPlatform();
+
+// // Set the look and feel before opening the window
+// try {
+// platform.setLookAndFeel();
+// } catch (Exception e) {
+// System.err.println("Non-fatal error while setting the Look & Feel.");
+// System.err.println("The error message follows, however Processing should run fine.");
+// System.err.println(e.getMessage());
+// //e.printStackTrace();
+// }
+
+ // Use native popups so they don't look so crappy on osx
+ JPopupMenu.setDefaultLightWeightPopupEnabled(false);
+
+ // Don't put anything above this line that might make GUI,
+ // because the platform has to be inited properly first.
+
+ // Make sure a full JDK is installed
+ initRequirements();
+
+ // run static initialization that grabs all the prefs
+ Preferences.init(null);
+
+ // setup the theme coloring fun
+ Theme.init();
+
+ if (Base.isMacOS()) {
+ String properMenuBar = "apple.laf.useScreenMenuBar";
+ String menubar = Preferences.get(properMenuBar);
+ if (menubar != null) {
+ // Get the current menu bar setting and use it
+ System.setProperty(properMenuBar, menubar);
+
+ } else {
+ // 10.4 is not affected, 10.5 (and prolly 10.6) are
+ if (System.getProperty("os.version").startsWith("10.4")) {
+ // Don't bother checking next time
+ Preferences.set(properMenuBar, "true");
+ // Also set the menubar now
+ System.setProperty(properMenuBar, "true");
+
+ } else {
+ // Running 10.5 or 10.6 or whatever, give 'em the business
+ String warning =
+ "" +
+ " " +
+ "The standard menu bar has been disabled." +
+ "
Due to an Apple bug, the Processing menu bar " +
+ "is unusable on Mac OS X 10.5. " +
+ "As a workaround, the menu bar will be placed inside " +
+ "the editor window. This setting can be changed in the " +
+ "Preferences window. If this bug makes you sad, " +
+ "please contact Apple via bugreporter.apple.com.
" +
+ " ";
+ Object[] options = { "OK", "More Info" };
+ int result = JOptionPane.showOptionDialog(new Frame(),
+ warning,
+ "Menu Bar Problem",
+ JOptionPane.YES_NO_OPTION,
+ JOptionPane.WARNING_MESSAGE,
+ null,
+ options,
+ options[0]);
+ if (result == -1) {
+ // They hit ESC or closed the window, so just hide it for now
+ // But don't bother setting the preference in the file
+ } else {
+ // Shut off in the preferences for next time
+ Preferences.set(properMenuBar, "false");
+ if (result == 1) { // More Info
+ Base.openURL("http://dev.processing.org/bugs/show_bug.cgi?id=786");
+ }
+ }
+ // Whether or not canceled, set to false (right now) if we're on 10.5
+ System.setProperty(properMenuBar, "false");
+ }
+ }
+ }
+
+ // Set the look and feel before opening the window
+ // For 0158, moving it lower so that the apple.laf.useScreenMenuBar stuff works
+ try {
+ platform.setLookAndFeel();
+ } catch (Exception e) {
+ System.err.println("Non-fatal error while setting the Look & Feel.");
+ System.err.println("The error message follows, however Processing should run fine.");
+ System.err.println(e.getMessage());
+ //e.printStackTrace();
+ }
+
+ // Create a location for untitled sketches
+ untitledFolder = createTempFolder("untitled");
+ untitledFolder.deleteOnExit();
+
+ new Base(args);
+ }
+
+
+ static protected void setCommandLine() {
+ commandLine = true;
+ }
+
+
+ static protected boolean isCommandLine() {
+ return commandLine;
+ }
+
+
+ static protected void initPlatform() {
+ try {
+ Class platformClass = Class.forName("processing.app.Platform");
+ if (Base.isMacOS()) {
+ platformClass = Class.forName("processing.app.macosx.Platform");
+ } else if (Base.isWindows()) {
+ platformClass = Class.forName("processing.app.windows.Platform");
+ } else if (Base.isLinux()) {
+ platformClass = Class.forName("processing.app.linux.Platform");
+ }
+ platform = (Platform) platformClass.newInstance();
+ } catch (Exception e) {
+ Base.showError("Problem Setting the Platform",
+ "An unknown error occurred while trying to load\n" +
+ "platform-specific code for your machine.", e);
+ }
+ }
+
+
+ static protected void initRequirements() {
+ try {
+ Class.forName("com.sun.jdi.VirtualMachine");
+ } catch (ClassNotFoundException cnfe) {
+ Base.showPlatforms();
+ Base.showError("Please install JDK 1.5 or later",
+ "Processing requires a full JDK (not just a JRE)\n" +
+ "to run. Please install JDK 1.5 or later.\n" +
+ "More information can be found in the reference.", cnfe);
+ }
+ }
+
+
+ public Base(String[] args) {
+ platform.init(this);
+
+ // Get paths for the libraries and examples in the Processing folder
+ //String workingDirectory = System.getProperty("user.dir");
+ examplesFolder = getContentFile("examples");
+ librariesFolder = getContentFile("libraries");
+ toolsFolder = getContentFile("tools");
+
+ // Get the sketchbook path, and make sure it's set properly
+ String sketchbookPath = Preferences.get("sketchbook.path");
+
+ // 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.
+ if (sketchbookPath != null) {
+ File skechbookFolder = new File(sketchbookPath);
+ if (!skechbookFolder.exists()) {
+ Base.showWarning("Sketchbook folder disappeared",
+ "The sketchbook folder no longer exists.\n" +
+ "Processing will switch to the default sketchbook\n" +
+ "location, and create a new sketchbook folder if\n" +
+ "necessary. Procesing will then stop talking about\n" +
+ "himself in the third person.", null);
+ sketchbookPath = null;
+ }
+ }
+
+ // If not path is set, get the default sketchbook folder for this platform
+ if (sketchbookPath == null) {
+ File defaultFolder = getDefaultSketchbookFolder();
+ Preferences.set("sketchbook.path", defaultFolder.getAbsolutePath());
+ if (!defaultFolder.exists()) {
+ defaultFolder.mkdirs();
+ }
+ }
+
+ // Check if there were previously opened sketches to be restored
+ boolean opened = restoreSketches();
+
+ // Check if any files were passed in on the command line
+ for (int i = 0; i < args.length; i++) {
+ String path = args[i];
+ // Fix a problem with systems that use a non-ASCII languages. Paths are
+ // being passed in with 8.3 syntax, which makes the sketch loader code
+ // unhappy, since the sketch folder naming doesn't match up correctly.
+ // http://dev.processing.org/bugs/show_bug.cgi?id=1089
+ if (isWindows()) {
+ try {
+ File file = new File(args[i]);
+ path = file.getCanonicalPath();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ if (handleOpen(path) != null) {
+ opened = true;
+ }
+ }
+
+ // Create a new empty window (will be replaced with any files to be opened)
+ if (!opened) {
+ handleNew();
+ }
+
+ // check for updates
+ if (Preferences.getBoolean("update.check")) {
+ new UpdateCheck(this);
+ }
+ }
+
+
+ /**
+ * Post-constructor setup for the editor area. Loads the last
+ * sketch that was used (if any), and restores other Editor settings.
+ * The complement to "storePreferences", this is called when the
+ * application is first launched.
+ */
+ protected boolean restoreSketches() {
+ // figure out window placement
+
+ Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
+ boolean windowPositionValid = true;
+
+ if (Preferences.get("last.screen.height") != null) {
+ // if screen size has changed, the window coordinates no longer
+ // make sense, so don't use them unless they're identical
+ int screenW = Preferences.getInteger("last.screen.width");
+ int screenH = Preferences.getInteger("last.screen.height");
+
+ if ((screen.width != screenW) || (screen.height != screenH)) {
+ windowPositionValid = false;
+ }
+ /*
+ int windowX = Preferences.getInteger("last.window.x");
+ int windowY = Preferences.getInteger("last.window.y");
+ if ((windowX < 0) || (windowY < 0) ||
+ (windowX > screenW) || (windowY > screenH)) {
+ windowPositionValid = false;
+ }
+ */
+ } else {
+ windowPositionValid = false;
+ }
+
+ // Iterate through all sketches that were open last time p5 was running.
+ // If !windowPositionValid, then ignore the coordinates found for each.
+
+ // Save the sketch path and window placement for each open sketch
+ int count = Preferences.getInteger("last.sketch.count");
+ int opened = 0;
+ for (int i = 0; i < count; i++) {
+ String path = Preferences.get("last.sketch" + i + ".path");
+ int[] location;
+ if (windowPositionValid) {
+ String locationStr = Preferences.get("last.sketch" + i + ".location");
+ location = PApplet.parseInt(PApplet.split(locationStr, ','));
+ } else {
+ location = nextEditorLocation();
+ }
+ // If file did not exist, null will be returned for the Editor
+ if (handleOpen(path, location) != null) {
+ opened++;
+ }
+ }
+ return (opened > 0);
+ }
+
+
+ /**
+ * Store list of sketches that are currently open.
+ * Called when the application is quitting and documents are still open.
+ */
+ protected void storeSketches() {
+ // Save the width and height of the screen
+ Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
+ Preferences.setInteger("last.screen.width", screen.width);
+ Preferences.setInteger("last.screen.height", screen.height);
+
+ String untitledPath = untitledFolder.getAbsolutePath();
+
+ // Save the sketch path and window placement for each open sketch
+ int index = 0;
+ for (Editor editor : editors) {
+ String path = editor.getSketch().getMainFilePath();
+ // In case of a crash, save untitled sketches if they contain changes.
+ // (Added this for release 0158, may not be a good idea.)
+ if (path.startsWith(untitledPath) &&
+ !editor.getSketch().isModified()) {
+ continue;
+ }
+ Preferences.set("last.sketch" + index + ".path", path);
+
+ int[] location = editor.getPlacement();
+ String locationStr = PApplet.join(PApplet.str(location), ",");
+ Preferences.set("last.sketch" + index + ".location", locationStr);
+ index++;
+ }
+ Preferences.setInteger("last.sketch.count", index);
+ }
+
+
+ // If a sketch is untitled on quit, may need to store the new name
+ // rather than the location from the temp folder.
+ protected void storeSketchPath(Editor editor, int index) {
+ String path = editor.getSketch().getMainFilePath();
+ String untitledPath = untitledFolder.getAbsolutePath();
+ if (path.startsWith(untitledPath)) {
+ path = "";
+ }
+ Preferences.set("last.sketch" + index + ".path", path);
+ }
+
+
+ /*
+ public void storeSketch(Editor editor) {
+ int index = -1;
+ for (int i = 0; i < editorCount; i++) {
+ if (editors[i] == editor) {
+ index = i;
+ break;
+ }
+ }
+ if (index == -1) {
+ System.err.println("Problem storing sketch " + editor.sketch.name);
+ } else {
+ String path = editor.sketch.getMainFilePath();
+ Preferences.set("last.sketch" + index + ".path", path);
+ }
+ }
+ */
+
+
+ // .................................................................
+
+
+ // Because of variations in native windowing systems, no guarantees about
+ // changes to the focused and active Windows can be made. Developers must
+ // never assume that this Window is the focused or active Window until this
+ // Window receives a WINDOW_GAINED_FOCUS or WINDOW_ACTIVATED event.
+ protected void handleActivated(Editor whichEditor) {
+ activeEditor = whichEditor;
+
+ // set the current window to be the console that's getting output
+ EditorConsole.setEditor(activeEditor);
+ }
+
+
+ protected int[] nextEditorLocation() {
+ Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
+ int defaultWidth = Preferences.getInteger("default.window.width");
+ int defaultHeight = Preferences.getInteger("default.window.height");
+
+ if (activeEditor == null) {
+ // If no current active editor, use default placement
+ return new int[] {
+ (screen.width - defaultWidth) / 2,
+ (screen.height - defaultHeight) / 2,
+ defaultWidth, defaultHeight, 0
+ };
+
+ } else {
+ // With a currently active editor, open the new window
+ // using the same dimensions, but offset slightly.
+ synchronized (editors) {
+ final int OVER = 50;
+ // In release 0160, don't
+ //location = activeEditor.getPlacement();
+ Editor lastOpened = editors.get(editors.size() - 1);
+ int[] location = lastOpened.getPlacement();
+ // Just in case the bounds for that window are bad
+ location[0] += OVER;
+ location[1] += OVER;
+
+ if (location[0] == OVER ||
+ location[2] == OVER ||
+ location[0] + location[2] > screen.width ||
+ location[1] + location[3] > screen.height) {
+ // Warp the next window to a randomish location on screen.
+ return new int[] {
+ (int) (Math.random() * (screen.width - defaultWidth)),
+ (int) (Math.random() * (screen.height - defaultHeight)),
+ defaultWidth, defaultHeight, 0
+ };
+ }
+
+ return location;
+ }
+ }
+ }
+
+
+ // .................................................................
+
+
+ boolean breakTime = false;
+ String[] months = {
+ "jan", "feb", "mar", "apr", "may", "jun",
+ "jul", "aug", "sep", "oct", "nov", "dec"
+ };
+
+ /**
+ * Handle creating a sketch folder, return its base .pde file
+ * or null if the operation was canceled.
+ * @param shift whether shift is pressed, which will invert prompt setting
+ * @param noPrompt disable prompt, no matter the setting
+ */
+ protected String createNewUntitled() throws IOException {
+ File newbieDir = null;
+ String newbieName = null;
+
+ // In 0126, untitled sketches will begin in the temp folder,
+ // and then moved to a new location because Save will default to Save As.
+ File sketchbookDir = getSketchbookFolder();
+ File newbieParentDir = untitledFolder;
+
+ // Use a generic name like sketch_031008a, the date plus a char
+ int index = 0;
+ //SimpleDateFormat formatter = new SimpleDateFormat("yyMMdd");
+ //SimpleDateFormat formatter = new SimpleDateFormat("MMMdd");
+ //String purty = formatter.format(new Date()).toLowerCase();
+ Calendar cal = Calendar.getInstance();
+ int day = cal.get(Calendar.DAY_OF_MONTH); // 1..31
+ int month = cal.get(Calendar.MONTH); // 0..11
+ String purty = months[month] + PApplet.nf(day, 2);
+ do {
+ if (index == 26) {
+ // In 0159, avoid running past z by sending people outdoors.
+ if (!breakTime) {
+ Base.showWarning("Time for a Break",
+ "You've reached the limit for auto naming of new sketches\n" +
+ "for the day. How about going for a walk instead?", null);
+ breakTime = true;
+ } else {
+ Base.showWarning("Sunshine",
+ "No really, time for some fresh air for you.", null);
+ }
+ return null;
+ }
+ newbieName = "sketch_" + purty + ((char) ('a' + index));
+ newbieDir = new File(newbieParentDir, newbieName);
+ index++;
+ // Make sure it's not in the temp folder *and* it's not in the sketchbook
+ } while (newbieDir.exists() || new File(sketchbookDir, newbieName).exists());
+
+ // Make the directory for the new sketch
+ newbieDir.mkdirs();
+
+ // Make an empty pde file
+ File newbieFile = new File(newbieDir, newbieName + ".pde");
+ new FileOutputStream(newbieFile); // create the file
+ return newbieFile.getAbsolutePath();
+ }
+
+
+ /**
+ * Create a new untitled document in a new sketch window.
+ */
+ public void handleNew() {
+ try {
+ String path = createNewUntitled();
+ if (path != null) {
+ Editor editor = handleOpen(path);
+ editor.untitled = true;
+ }
+
+ } catch (IOException e) {
+ if (activeEditor != null) {
+ activeEditor.statusError(e);
+ }
+ }
+ }
+
+
+ /**
+ * Replace the sketch in the current window with a new untitled document.
+ */
+ public void handleNewReplace() {
+ if (!activeEditor.checkModified(false)) {
+ return; // sketch was modified, and user canceled
+ }
+ // Close the running window, avoid window boogers with multiple sketches
+ activeEditor.internalCloseRunner();
+
+ // Actually replace things
+ handleNewReplaceImpl();
+ }
+
+
+ protected void handleNewReplaceImpl() {
+ try {
+ String path = createNewUntitled();
+ if (path != null) {
+ activeEditor.handleOpenInternal(path);
+ activeEditor.untitled = true;
+ }
+// return true;
+
+ } catch (IOException e) {
+ activeEditor.statusError(e);
+// return false;
+ }
+ }
+
+
+ /**
+ * Open a sketch, replacing the sketch in the current window.
+ * @param path Location of the primary pde file for the sketch.
+ */
+ public void handleOpenReplace(String path) {
+ if (!activeEditor.checkModified(false)) {
+ return; // sketch was modified, and user canceled
+ }
+ // Close the running window, avoid window boogers with multiple sketches
+ activeEditor.internalCloseRunner();
+
+ boolean loaded = activeEditor.handleOpenInternal(path);
+ if (!loaded) {
+ // replace the document without checking if that's ok
+ handleNewReplaceImpl();
+ }
+ }
+
+
+ /**
+ * Prompt for a sketch to open, and open it in a new window.
+ */
+ public void handleOpenPrompt() {
+ // get the frontmost window frame for placing file dialog
+ FileDialog fd = new FileDialog(activeEditor,
+ "Open a Processing sketch...",
+ FileDialog.LOAD);
+ // This was annoying people, so disabled it in 0125.
+ //fd.setDirectory(Preferences.get("sketchbook.path"));
+ //fd.setDirectory(getSketchbookPath());
+
+ // Only show .pde files as eligible bachelors
+ fd.setFilenameFilter(new FilenameFilter() {
+ public boolean accept(File dir, String name) {
+ // TODO this doesn't seem to ever be used. AWESOME.
+ //System.out.println("check filter on " + dir + " " + name);
+ return name.toLowerCase().endsWith(".pde");
+ }
+ });
+
+ fd.setVisible(true);
+
+ String directory = fd.getDirectory();
+ String filename = fd.getFile();
+
+ // User canceled selection
+ if (filename == null) return;
+
+ File inputFile = new File(directory, filename);
+ handleOpen(inputFile.getAbsolutePath());
+ }
+
+
+ /**
+ * Open a sketch in a new window.
+ * @param path Path to the pde file for the sketch in question
+ * @return the Editor object, so that properties (like 'untitled')
+ * can be set by the caller
+ */
+ public Editor handleOpen(String path) {
+ return handleOpen(path, nextEditorLocation());
+ }
+
+
+ protected Editor handleOpen(String path, int[] location) {
+ File file = new File(path);
+ if (!file.exists()) return null;
+
+ // Cycle through open windows to make sure that it's not already open.
+ for (Editor editor : editors) {
+ if (editor.getSketch().getMainFilePath().equals(path)) {
+ editor.toFront();
+ return editor;
+ }
+ }
+
+ // If the active editor window is an untitled, and un-modified document,
+ // just replace it with the file that's being opened.
+// if (activeEditor != null) {
+// Sketch activeSketch = activeEditor.sketch;
+// if (activeSketch.isUntitled() && !activeSketch.isModified()) {
+// // if it's an untitled, unmodified document, it can be replaced.
+// // except in cases where a second blank window is being opened.
+// if (!path.startsWith(untitledFolder.getAbsolutePath())) {
+// activeEditor.handleOpenUnchecked(path, 0, 0, 0, 0);
+// return activeEditor;
+// }
+// }
+// }
+
+ Editor editor = new Editor(this, path, location);
+
+ // Make sure that the sketch actually loaded
+ if (editor.getSketch() == null) {
+ return null; // Just walk away quietly
+ }
+
+// if (editors == null) {
+// editors = new Editor[5];
+// }
+// if (editorCount == editors.length) {
+// editors = (Editor[]) PApplet.expand(editors);
+// }
+// editors[editorCount++] = editor;
+ editors.add(editor);
+
+// if (markedForClose != null) {
+// Point p = markedForClose.getLocation();
+// handleClose(markedForClose, false);
+// // open the new window in
+// editor.setLocation(p);
+// }
+
+ // now that we're ready, show the window
+ // (don't do earlier, cuz we might move it based on a window being closed)
+ editor.setVisible(true);
+
+ return editor;
+ }
+
+
+ /**
+ * Close a sketch as specified by its editor window.
+ * @param editor Editor object of the sketch to be closed.
+ * @return true if succeeded in closing, false if canceled.
+ */
+ public boolean handleClose(Editor editor) {
+ // Check if modified
+ if (!editor.checkModified(false)) {
+ return false;
+ }
+
+ // Close the running window, avoid window boogers with multiple sketches
+ editor.internalCloseRunner();
+
+ if (editors.size() == 1) {
+ // For 0158, when closing the last window /and/ it was already an
+ // untitled sketch, just give up and let the user quit.
+// if (Preferences.getBoolean("sketchbook.closing_last_window_quits") ||
+// (editor.untitled && !editor.getSketch().isModified())) {
+ if (Base.isMacOS()) {
+ Object[] options = { "OK", "Cancel" };
+ String prompt =
+ " " +
+ " " +
+ "Are you sure you want to Quit?" +
+ "
Closing the last open sketch will quit Processing.";
+
+ int result = JOptionPane.showOptionDialog(editor,
+ prompt,
+ "Quit",
+ JOptionPane.YES_NO_OPTION,
+ JOptionPane.QUESTION_MESSAGE,
+ null,
+ options,
+ options[0]);
+ if (result == JOptionPane.NO_OPTION ||
+ result == JOptionPane.CLOSED_OPTION) {
+ return false;
+ }
+ }
+
+ // This will store the sketch count as zero
+ editors.remove(editor);
+ storeSketches();
+
+ // Save out the current prefs state
+ Preferences.save();
+
+ // Since this wasn't an actual Quit event, call System.exit()
+ System.exit(0);
+
+ } else {
+ // More than one editor window open,
+ // proceed with closing the current window.
+ editor.setVisible(false);
+ editor.dispose();
+// for (int i = 0; i < editorCount; i++) {
+// if (editor == editors[i]) {
+// for (int j = i; j < editorCount-1; j++) {
+// editors[j] = editors[j+1];
+// }
+// editorCount--;
+// // Set to null so that garbage collection occurs
+// editors[editorCount] = null;
+// }
+// }
+ editors.remove(editor);
+ }
+ return true;
+ }
+
+
+ /**
+ * Handler for File → Quit.
+ * @return false if canceled, true otherwise.
+ */
+ public boolean handleQuit() {
+ // If quit is canceled, this will be replaced anyway
+ // by a later handleQuit() that is not canceled.
+ storeSketches();
+
+ if (handleQuitEach()) {
+ // make sure running sketches close before quitting
+ for (Editor editor : editors) {
+ editor.internalCloseRunner();
+ }
+ // Save out the current prefs state
+ Preferences.save();
+
+ if (!Base.isMacOS()) {
+ // If this was fired from the menu or an AppleEvent (the Finder),
+ // then Mac OS X will send the terminate signal itself.
+ System.exit(0);
+ }
+ return true;
+ }
+ return false;
+ }
+
+
+ /**
+ * Attempt to close each open sketch in preparation for quitting.
+ * @return false if canceled along the way
+ */
+ protected boolean handleQuitEach() {
+ int index = 0;
+ for (Editor editor : editors) {
+ if (editor.checkModified(true)) {
+ // Update to the new/final sketch path for this fella
+ storeSketchPath(editor, index);
+ index++;
+
+ } else {
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+ // .................................................................
+
+
+ /**
+ * Asynchronous version of menu rebuild to be used on save and rename
+ * to prevent the interface from locking up until the menus are done.
+ */
+ protected void rebuildSketchbookMenus() {
+ //System.out.println("async enter");
+ //new Exception().printStackTrace();
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ //System.out.println("starting rebuild");
+ rebuildSketchbookMenu(Editor.sketchbookMenu);
+ rebuildToolbarMenu(Editor.toolbarMenu);
+ //System.out.println("done with rebuild");
+ }
+ });
+ //System.out.println("async exit");
+ }
+
+
+ protected void rebuildToolbarMenu(JMenu menu) {
+ JMenuItem item;
+ menu.removeAll();
+
+ //System.out.println("rebuilding toolbar menu");
+ // Add the single "Open" item
+ item = Editor.newJMenuItem("Open...", 'O');
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ handleOpenPrompt();
+ }
+ });
+ menu.add(item);
+ menu.addSeparator();
+
+ // Add a list of all sketches and subfolders
+ try {
+ boolean sketches = addSketches(menu, getSketchbookFolder(), true);
+ if (sketches) menu.addSeparator();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ //System.out.println("rebuilding examples menu");
+ // Add each of the subfolders of examples directly to the menu
+ try {
+ addSketches(menu, examplesFolder, true);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ protected void rebuildSketchbookMenu(JMenu menu) {
+ //System.out.println("rebuilding sketchbook menu");
+ //new Exception().printStackTrace();
+ try {
+ menu.removeAll();
+ addSketches(menu, getSketchbookFolder(), false);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ public void rebuildImportMenu(JMenu importMenu) {
+ //System.out.println("rebuilding import menu");
+ importMenu.removeAll();
+
+ // reset the table mapping imports to libraries
+ importToLibraryTable = new HashMap();
+
+ // Add libraries found in the sketchbook folder
+ try {
+ File sketchbookLibraries = getSketchbookLibrariesFolder();
+ boolean found = addLibraries(importMenu, sketchbookLibraries);
+ if (found) importMenu.addSeparator();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ // Add from the "libraries" subfolder in the Processing directory
+ try {
+ addLibraries(importMenu, librariesFolder);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ public void rebuildExamplesMenu(JMenu menu) {
+ //System.out.println("rebuilding examples menu");
+
+ try {
+ menu.removeAll();
+ addSketches(menu, examplesFolder, false);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ /**
+ * Scan a folder recursively, and add any sketches found to the menu
+ * specified. Set the openReplaces parameter to true when opening the sketch
+ * should replace the sketch in the current window, or false when the
+ * sketch should open in a new window.
+ */
+ protected boolean addSketches(JMenu menu, File folder,
+ final boolean openReplaces) throws IOException {
+ // skip .DS_Store files, etc (this shouldn't actually be necessary)
+ if (!folder.isDirectory()) return false;
+
+ String[] list = folder.list();
+ // If a bad folder or unreadable or whatever, this will come back null
+ if (list == null) return false;
+
+ // Alphabetize list, since it's not always alpha order
+ Arrays.sort(list, String.CASE_INSENSITIVE_ORDER);
+ //processing.core.PApplet.println("adding sketches " + folder.getAbsolutePath());
+ //PApplet.println(list);
+
+ ActionListener listener = new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ String path = e.getActionCommand();
+ if (new File(path).exists()) {
+ if (openReplaces) {
+ handleOpenReplace(path);
+ } else {
+ handleOpen(path);
+ }
+ } else {
+ showWarning("Sketch Does Not Exist",
+ "The selected sketch no longer exists.\n" +
+ "You may need to restart Processing to update\n" +
+ "the sketchbook menu.", null);
+ }
+ }
+ };
+ // offers no speed improvement
+ //menu.addActionListener(listener);
+
+ boolean ifound = false;
+
+ for (int i = 0; i < list.length; i++) {
+ if ((list[i].charAt(0) == '.') ||
+ list[i].equals("CVS")) continue;
+
+ File subfolder = new File(folder, list[i]);
+ if (!subfolder.isDirectory()) continue;
+
+ File entry = new File(subfolder, list[i] + ".pde");
+ // if a .pde file of the same prefix as the folder exists..
+ if (entry.exists()) {
+ //String sanityCheck = sanitizedName(list[i]);
+ //if (!sanityCheck.equals(list[i])) {
+ if (!Sketch.isSanitaryName(list[i])) {
+ if (!builtOnce) {
+ String complaining =
+ "The sketch \"" + list[i] + "\" cannot be used.\n" +
+ "Sketch names must contain only basic letters and numbers\n" +
+ "(ASCII-only with no spaces, " +
+ "and it cannot start with a number).\n" +
+ "To get rid of this message, remove the sketch from\n" +
+ entry.getAbsolutePath();
+ Base.showMessage("Ignoring sketch with bad name", complaining);
+ }
+ continue;
+ }
+
+ JMenuItem item = new JMenuItem(list[i]);
+ item.addActionListener(listener);
+ item.setActionCommand(entry.getAbsolutePath());
+ menu.add(item);
+ ifound = true;
+
+ } else {
+ // not a sketch folder, but maybe a subfolder containing sketches
+ JMenu submenu = new JMenu(list[i]);
+ // needs to be separate var
+ // otherwise would set ifound to false
+ boolean found = addSketches(submenu, subfolder, openReplaces); //, false);
+ if (found) {
+ menu.add(submenu);
+ ifound = true;
+ }
+ }
+ }
+ return ifound; // actually ignored, but..
+ }
+
+
+ protected boolean addLibraries(JMenu menu, File folder) throws IOException {
+ if (!folder.isDirectory()) return false;
+
+ String list[] = folder.list(new FilenameFilter() {
+ public boolean accept(File dir, String name) {
+ // skip .DS_Store files, .svn folders, etc
+ if (name.charAt(0) == '.') return false;
+ if (name.equals("CVS")) return false;
+ return (new File(dir, name).isDirectory());
+ }
+ });
+ // if a bad folder or something like that, this might come back null
+ if (list == null) return false;
+
+ // alphabetize list, since it's not always alpha order
+ // replaced hella slow bubble sort with this feller for 0093
+ Arrays.sort(list, String.CASE_INSENSITIVE_ORDER);
+
+ ActionListener listener = new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ activeEditor.getSketch().importLibrary(e.getActionCommand());
+ }
+ };
+
+ boolean ifound = false;
+
+ for (String libraryName : list) {
+ File subfolder = new File(folder, libraryName);
+ File libraryFolder = new File(subfolder, "library");
+ File libraryJar = new File(libraryFolder, libraryName + ".jar");
+ // If a .jar file of the same prefix as the folder exists
+ // inside the 'library' subfolder of the sketch
+ if (libraryJar.exists()) {
+ String sanityCheck = Sketch.sanitizeName(libraryName);
+ if (!sanityCheck.equals(libraryName)) {
+ String mess =
+ "The library \"" + libraryName + "\" cannot be used.\n" +
+ "Library names must contain only basic letters and numbers.\n" +
+ "(ascii only and no spaces, and it cannot start with a number)";
+ Base.showMessage("Ignoring bad library name", mess);
+ continue;
+ }
+
+ // get the path for all .jar files in this code folder
+ String libraryClassPath =
+ Compiler.contentsToClassPath(libraryFolder);
+ // grab all jars and classes from this folder,
+ // and append them to the library classpath
+ librariesClassPath +=
+ File.pathSeparatorChar + libraryClassPath;
+ // need to associate each import with a library folder
+ String packages[] =
+ Compiler.packageListFromClassPath(libraryClassPath);
+ for (String pkg : packages) {
+ importToLibraryTable.put(pkg, libraryFolder);
+ }
+
+ JMenuItem item = new JMenuItem(libraryName);
+ item.addActionListener(listener);
+ item.setActionCommand(libraryJar.getAbsolutePath());
+ menu.add(item);
+ ifound = true;
+
+ } else { // not a library, but is still a folder, so recurse
+ JMenu submenu = new JMenu(libraryName);
+ // needs to be separate var, otherwise would set ifound to false
+ boolean found = addLibraries(submenu, subfolder);
+ if (found) {
+ menu.add(submenu);
+ ifound = true;
+ }
+ }
+ }
+ return ifound;
+ }
+
+
+ // .................................................................
+
+
+ /**
+ * Show the About box.
+ */
+ public void handleAbout() {
+ final Image image = Base.getLibImage("about.jpg", activeEditor);
+ final Window window = new Window(activeEditor) {
+ public void paint(Graphics g) {
+ g.drawImage(image, 0, 0, null);
+
+ Graphics2D g2 = (Graphics2D) g;
+ g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
+ RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
+
+ g.setFont(new Font("SansSerif", Font.PLAIN, 11));
+ g.setColor(Color.white);
+ g.drawString(Base.VERSION_NAME, 50, 30);
+ }
+ };
+ window.addMouseListener(new MouseAdapter() {
+ public void mousePressed(MouseEvent e) {
+ window.dispose();
+ }
+ });
+ int w = image.getWidth(activeEditor);
+ int h = image.getHeight(activeEditor);
+ Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
+ window.setBounds((screen.width-w)/2, (screen.height-h)/2, w, h);
+ window.setVisible(true);
+ }
+
+
+ /**
+ * Show the Preferences window.
+ */
+ public void handlePrefs() {
+ if (preferencesFrame == null) preferencesFrame = new Preferences();
+ preferencesFrame.showFrame(activeEditor);
+ }
+
+
+ // ...................................................................
+
+
+ /**
+ * Get list of platform constants.
+ */
+// static public int[] getPlatforms() {
+// return platforms;
+// }
+
+
+// static public int getPlatform() {
+// String osname = System.getProperty("os.name");
+//
+// if (osname.indexOf("Mac") != -1) {
+// return PConstants.MACOSX;
+//
+// } else if (osname.indexOf("Windows") != -1) {
+// return PConstants.WINDOWS;
+//
+// } else if (osname.equals("Linux")) { // true for the ibm vm
+// return PConstants.LINUX;
+//
+// } else {
+// return PConstants.OTHER;
+// }
+// }
+
+
+ static public String getPlatformName() {
+ String osname = System.getProperty("os.name");
+
+ if (osname.indexOf("Mac") != -1) {
+ return "macosx";
+
+ } else if (osname.indexOf("Windows") != -1) {
+ return "windows";
+
+ } else if (osname.equals("Linux")) { // true for the ibm vm
+ return "linux";
+
+ } else {
+ return "other";
+ }
+ }
+
+
+ /**
+ * Map a platform constant to its name.
+ * @param which PConstants.WINDOWS, PConstants.MACOSX, PConstants.LINUX
+ * @return one of "windows", "macosx", or "linux"
+ */
+ static public String getPlatformName(int which) {
+ return platformNames.get(which);
+ }
+
+
+ static public int getPlatformIndex(String what) {
+ Integer entry = platformIndices.get(what);
+ return (entry == null) ? -1 : entry.intValue();
+ }
+
+
+ // These were changed to no longer rely on PApplet and PConstants because
+ // of conflicts that could happen with older versions of core.jar, where
+ // the MACOSX constant would instead read as the LINUX constant.
+
+
+ /**
+ * returns true if Processing is running on a Mac OS X machine.
+ */
+ static public boolean isMacOS() {
+ //return PApplet.platform == PConstants.MACOSX;
+ return System.getProperty("os.name").indexOf("Mac") != -1;
+ }
+
+
+ /**
+ * returns true if running on windows.
+ */
+ static public boolean isWindows() {
+ //return PApplet.platform == PConstants.WINDOWS;
+ return System.getProperty("os.name").indexOf("Windows") != -1;
+ }
+
+
+ /**
+ * true if running on linux.
+ */
+ static public boolean isLinux() {
+ //return PApplet.platform == PConstants.LINUX;
+ return System.getProperty("os.name").indexOf("Linux") != -1;
+ }
+
+
+ // .................................................................
+
+
+ static public File getSettingsFolder() {
+ File settingsFolder = null;
+
+ String preferencesPath = Preferences.get("settings.path");
+ if (preferencesPath != null) {
+ settingsFolder = new File(preferencesPath);
+
+ } else {
+ try {
+ settingsFolder = platform.getSettingsFolder();
+ } catch (Exception e) {
+ showError("Problem getting data folder",
+ "Error getting the Processing data folder.", e);
+ }
+ }
+
+ // create the folder if it doesn't exist already
+ if (!settingsFolder.exists()) {
+ if (!settingsFolder.mkdirs()) {
+ showError("Settings issues",
+ "Processing cannot run because it could not\n" +
+ "create a folder to store your settings.", null);
+ }
+ }
+ return settingsFolder;
+ }
+
+
+ /**
+ * Convenience method to get a File object for the specified filename inside
+ * the settings folder.
+ * For now, only used by Preferences to get the preferences.txt file.
+ * @param filename A file inside the settings folder.
+ * @return filename wrapped as a File object inside the settings folder
+ */
+ static public File getSettingsFile(String filename) {
+ return new File(getSettingsFolder(), filename);
+ }
+
+
+ static public File getBuildFolder() {
+ if (buildFolder == null) {
+ String buildPath = Preferences.get("build.path");
+ if (buildPath != null) {
+ buildFolder = new File(buildPath);
+
+ } else {
+ //File folder = new File(getTempFolder(), "build");
+ //if (!folder.exists()) folder.mkdirs();
+ buildFolder = createTempFolder("build");
+ buildFolder.deleteOnExit();
+ }
+ }
+ return buildFolder;
+ }
+
+
+ /**
+ * Get the path to the platform's temporary folder, by creating
+ * a temporary temporary file and getting its parent folder.
+ *
+ * Modified for revision 0094 to actually make the folder randomized
+ * to avoid conflicts in multi-user environments. (Bug 177)
+ */
+ static public File createTempFolder(String name) {
+ try {
+ File folder = File.createTempFile(name, null);
+ //String tempPath = ignored.getParent();
+ //return new File(tempPath);
+ folder.delete();
+ folder.mkdirs();
+ return folder;
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+
+ static public String getExamplesPath() {
+ return examplesFolder.getAbsolutePath();
+ }
+
+
+ static public String getLibrariesPath() {
+ return librariesFolder.getAbsolutePath();
+ }
+
+
+ static public File getToolsFolder() {
+ return toolsFolder;
+ }
+
+
+ static public String getToolsPath() {
+ return toolsFolder.getAbsolutePath();
+ }
+
+
+ static public File getSketchbookFolder() {
+ return new File(Preferences.get("sketchbook.path"));
+ }
+
+
+ static public File getSketchbookLibrariesFolder() {
+ return new File(getSketchbookFolder(), "libraries");
+ }
+
+
+ protected File getDefaultSketchbookFolder() {
+ File sketchbookFolder = null;
+ try {
+ sketchbookFolder = platform.getDefaultSketchbookFolder();
+ } catch (Exception e) { }
+
+ if (sketchbookFolder == null) {
+ sketchbookFolder = promptSketchbookLocation();
+ }
+
+ // create the folder if it doesn't exist already
+ boolean result = true;
+ if (!sketchbookFolder.exists()) {
+ result = sketchbookFolder.mkdirs();
+ }
+
+ if (!result) {
+ showError("You forgot your sketchbook",
+ "Processing cannot run because it could not\n" +
+ "create a folder to store your sketchbook.", null);
+ }
+
+ return sketchbookFolder;
+ }
+
+
+ /**
+ * Check for a new sketchbook location.
+ */
+ static protected File promptSketchbookLocation() {
+ File folder = null;
+
+ folder = new File(System.getProperty("user.home"), "sketchbook");
+ if (!folder.exists()) {
+ folder.mkdirs();
+ return folder;
+ }
+
+ String prompt = "Select (or create new) folder for sketches...";
+ folder = Base.selectFolder(prompt, null, null);
+ if (folder == null) {
+ System.exit(0);
+ }
+ return folder;
+ }
+
+
+ // .................................................................
+
+
+ /**
+ * Implements the cross-platform headache of opening URLs
+ * TODO This code should be replaced by PApplet.link(),
+ * however that's not a static method (because it requires
+ * an AppletContext when used as an applet), so it's mildly
+ * trickier than just removing this method.
+ */
+ static public void openURL(String url) {
+ try {
+ platform.openURL(url);
+
+ } catch (Exception e) {
+ showWarning("Problem Opening URL",
+ "Could not open the URL\n" + url, e);
+ }
+ }
+
+
+ /**
+ * Used to determine whether to disable the "Show Sketch Folder" option.
+ * @return true If a means of opening a folder is known to be available.
+ */
+ static protected boolean openFolderAvailable() {
+ return platform.openFolderAvailable();
+ }
+
+
+ /**
+ * Implements the other cross-platform headache of opening
+ * a folder in the machine's native file browser.
+ */
+ static public void openFolder(File file) {
+ try {
+ platform.openFolder(file);
+
+ } catch (Exception e) {
+ showWarning("Problem Opening Folder",
+ "Could not open the folder\n" + file.getAbsolutePath(), e);
+ }
+ }
+
+
+ // .................................................................
+
+
+ /**
+ * Prompt for a fodler and return it as a File object (or null).
+ * Implementation for choosing directories that handles both the
+ * Mac OS X hack to allow the native AWT file dialog, or uses
+ * the JFileChooser on other platforms. Mac AWT trick obtained from
+ * this post
+ * on the OS X Java dev archive which explains the cryptic note in
+ * Apple's Java 1.4 release docs about the special System property.
+ */
+ static public File selectFolder(String prompt, File folder, Frame frame) {
+ if (Base.isMacOS()) {
+ if (frame == null) frame = new Frame(); //.pack();
+ FileDialog fd = new FileDialog(frame, prompt, FileDialog.LOAD);
+ if (folder != null) {
+ fd.setDirectory(folder.getParent());
+ //fd.setFile(folder.getName());
+ }
+ System.setProperty("apple.awt.fileDialogForDirectories", "true");
+ fd.setVisible(true);
+ System.setProperty("apple.awt.fileDialogForDirectories", "false");
+ if (fd.getFile() == null) {
+ return null;
+ }
+ return new File(fd.getDirectory(), fd.getFile());
+
+ } else {
+ JFileChooser fc = new JFileChooser();
+ fc.setDialogTitle(prompt);
+ if (folder != null) {
+ fc.setSelectedFile(folder);
+ }
+ fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
+
+ int returned = fc.showOpenDialog(new JDialog());
+ if (returned == JFileChooser.APPROVE_OPTION) {
+ return fc.getSelectedFile();
+ }
+ }
+ return null;
+ }
+
+
+ // .................................................................
+
+
+ /**
+ * Give this Frame a Processing icon.
+ */
+ static public void setIcon(Frame frame) {
+ Image image = Toolkit.getDefaultToolkit().createImage(PApplet.ICON_IMAGE);
+ frame.setIconImage(image);
+ }
+
+
+ // someone needs to be slapped
+ //static KeyStroke closeWindowKeyStroke;
+
+ /**
+ * Return true if the key event was a Ctrl-W or an ESC,
+ * both indicators to close the window.
+ * Use as part of a keyPressed() event handler for frames.
+ */
+ /*
+ static public boolean isCloseWindowEvent(KeyEvent e) {
+ if (closeWindowKeyStroke == null) {
+ int modifiers = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
+ closeWindowKeyStroke = KeyStroke.getKeyStroke('W', modifiers);
+ }
+ return ((e.getKeyCode() == KeyEvent.VK_ESCAPE) ||
+ KeyStroke.getKeyStrokeForEvent(e).equals(closeWindowKeyStroke));
+ }
+ */
+
+
+ /**
+ * Registers key events for a Ctrl-W and ESC with an ActionListener
+ * that will take care of disposing the window.
+ */
+ static public void registerWindowCloseKeys(JRootPane root, //Window window,
+ ActionListener disposer) {
+ KeyStroke stroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
+ root.registerKeyboardAction(disposer, stroke,
+ JComponent.WHEN_IN_FOCUSED_WINDOW);
+
+ int modifiers = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
+ stroke = KeyStroke.getKeyStroke('W', modifiers);
+ root.registerKeyboardAction(disposer, stroke,
+ JComponent.WHEN_IN_FOCUSED_WINDOW);
+ }
+
+
+ // .................................................................
+
+
+ static public void showReference(String filename) {
+ File referenceFolder = Base.getContentFile("reference");
+ File referenceFile = new File(referenceFolder, filename);
+ openURL(referenceFile.getAbsolutePath());
+ }
+
+
+ static public void showReference() {
+ showReference("index.html");
+ }
+
+
+ static public void showEnvironment() {
+ showReference("environment" + File.separator + "index.html");
+ }
+
+
+ static public void showPlatforms() {
+ showReference("environment" + File.separator + "platforms.html");
+ }
+
+
+ static public void showTroubleshooting() {
+ showReference("troubleshooting" + File.separator + "index.html");
+ }
+
+
+ // .................................................................
+
+
+ /**
+ * "No cookie for you" type messages. Nothing fatal or all that
+ * much of a bummer, but something to notify the user about.
+ */
+ static public void showMessage(String title, String message) {
+ if (title == null) title = "Message";
+
+ if (commandLine) {
+ System.out.println(title + ": " + message);
+
+ } else {
+ JOptionPane.showMessageDialog(new Frame(), message, title,
+ JOptionPane.INFORMATION_MESSAGE);
+ }
+ }
+
+
+ /**
+ * Non-fatal error message with optional stack trace side dish.
+ */
+ static public void showWarning(String title, String message, Exception e) {
+ if (title == null) title = "Warning";
+
+ if (commandLine) {
+ System.out.println(title + ": " + message);
+
+ } else {
+ JOptionPane.showMessageDialog(new Frame(), message, title,
+ JOptionPane.WARNING_MESSAGE);
+ }
+ if (e != null) e.printStackTrace();
+ }
+
+
+ /**
+ * Show an error message that's actually fatal to the program.
+ * This is an error that can't be recovered. Use showWarning()
+ * for errors that allow P5 to continue running.
+ */
+ static public void showError(String title, String message, Throwable e) {
+ if (title == null) title = "Error";
+
+ if (commandLine) {
+ System.err.println(title + ": " + message);
+
+ } else {
+ JOptionPane.showMessageDialog(new Frame(), message, title,
+ JOptionPane.ERROR_MESSAGE);
+ }
+ if (e != null) e.printStackTrace();
+ System.exit(1);
+ }
+
+
+ // ...................................................................
+
+
+ /**
+ * Retrieve a path to something in the Processing folder. Eventually this
+ * may refer to the Contents subfolder of Processing.app, if we bundle things
+ * up as a single .app file with no additional folders.
+ */
+// static public String getContentsPath(String filename) {
+// String basePath = System.getProperty("user.dir");
+// /*
+// // do this later, when moving to .app package
+// if (PApplet.platform == PConstants.MACOSX) {
+// basePath = System.getProperty("processing.contents");
+// }
+// */
+// return basePath + File.separator + filename;
+// }
+
+
+ /**
+ * Get a path for something in the Processing lib folder.
+ */
+ /*
+ static public String getLibContentsPath(String filename) {
+ String libPath = getContentsPath("lib/" + filename);
+ File libDir = new File(libPath);
+ if (libDir.exists()) {
+ return libPath;
+ }
+// was looking into making this run from Eclipse, but still too much mess
+// libPath = getContents("build/shared/lib/" + what);
+// libDir = new File(libPath);
+// if (libDir.exists()) {
+// return libPath;
+// }
+ return null;
+ }
+ */
+
+ static public File getContentFile(String name) {
+ String path = System.getProperty("user.dir");
+
+ // Get a path to somewhere inside the .app folder
+ if (Base.isMacOS()) {
+// javaroot
+// $JAVAROOT
+ String javaroot = System.getProperty("javaroot");
+ if (javaroot != null) {
+ path = javaroot;
+ }
+ }
+ File working = new File(path);
+ return new File(working, name);
+ }
+
+
+ /**
+ * Get an image associated with the current color theme.
+ */
+ static public Image getThemeImage(String name, Component who) {
+ return getLibImage("theme/" + name, who);
+ }
+
+
+ /**
+ * Return an Image object from inside the Processing lib folder.
+ */
+ static public Image getLibImage(String name, Component who) {
+ Image image = null;
+ Toolkit tk = Toolkit.getDefaultToolkit();
+
+ File imageLocation = new File(getContentFile("lib"), name);
+ image = tk.getImage(imageLocation.getAbsolutePath());
+ MediaTracker tracker = new MediaTracker(who);
+ tracker.addImage(image, 0);
+ try {
+ tracker.waitForAll();
+ } catch (InterruptedException e) { }
+ return image;
+ }
+
+
+ /**
+ * Return an InputStream for a file inside the Processing lib folder.
+ */
+ static public InputStream getLibStream(String filename) throws IOException {
+ return new FileInputStream(new File(getContentFile("lib"), filename));
+ }
+
+
+ // ...................................................................
+
+
+ /**
+ * Get the number of lines in a file by counting the number of newline
+ * characters inside a String (and adding 1).
+ */
+ static public int countLines(String what) {
+ int count = 1;
+ for (char c : what.toCharArray()) {
+ if (c == '\n') count++;
+ }
+ return count;
+ }
+
+
+ /**
+ * Same as PApplet.loadBytes(), however never does gzip decoding.
+ */
+ static public byte[] loadBytesRaw(File file) throws IOException {
+ int size = (int) file.length();
+ FileInputStream input = new FileInputStream(file);
+ byte buffer[] = new byte[size];
+ int offset = 0;
+ int bytesRead;
+ while ((bytesRead = input.read(buffer, offset, size-offset)) != -1) {
+ offset += bytesRead;
+ if (bytesRead == 0) break;
+ }
+ input.close(); // weren't properly being closed
+ input = null;
+ return buffer;
+ }
+
+
+ static public void copyFile(File sourceFile,
+ File targetFile) throws IOException {
+ InputStream from =
+ new BufferedInputStream(new FileInputStream(sourceFile));
+ OutputStream to =
+ new BufferedOutputStream(new FileOutputStream(targetFile));
+ byte[] buffer = new byte[16 * 1024];
+ int bytesRead;
+ while ((bytesRead = from.read(buffer)) != -1) {
+ to.write(buffer, 0, bytesRead);
+ }
+ to.flush();
+ from.close(); // ??
+ from = null;
+ to.close(); // ??
+ to = null;
+
+ targetFile.setLastModified(sourceFile.lastModified());
+ }
+
+
+ /**
+ * Grab the contents of a file as a string.
+ */
+ static public String loadFile(File file) throws IOException {
+ return PApplet.join(PApplet.loadStrings(file), "\n");
+
+ /*
+ // empty code file.. no worries, might be getting filled up later
+ if (file.length() == 0) return "";
+
+ //FileInputStream fis = new FileInputStream(file);
+ //InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
+ //BufferedReader reader = new BufferedReader(isr);
+ BufferedReader reader = PApplet.createReader(file);
+
+ StringBuffer buffer = new StringBuffer();
+ String line = null;
+ while ((line = reader.readLine()) != null) {
+// char[] cc = line.toCharArray();
+// for (int i = 0; i < cc.length; i++) {
+// char c = cc[i];
+// if (c < 32 || c > 126) System.out.println("found " + c + " " + ((int) c));
+// }
+//
+ buffer.append(line);
+ buffer.append('\n');
+ }
+ reader.close();
+ return buffer.toString();
+ */
+ }
+
+
+ /**
+ * Spew the contents of a String object out to a file.
+ */
+ static public void saveFile(String str, File file) throws IOException {
+ PApplet.saveStrings(file, new String[] { str });
+ /*
+ ByteArrayInputStream bis = new ByteArrayInputStream(str.getBytes());
+ InputStreamReader isr = new InputStreamReader(bis);
+ BufferedReader reader = new BufferedReader(isr);
+
+ FileOutputStream fos = new FileOutputStream(file);
+ OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");
+ PrintWriter writer = new PrintWriter(osw);
+
+ String line = null;
+ while ((line = reader.readLine()) != null) {
+ writer.println(line);
+ }
+ writer.flush();
+ writer.close();
+ */
+ }
+
+
+ /**
+ * Copy a folder from one place to another. This ignores all dot files and
+ * folders found in the source directory, to avoid copying silly .DS_Store
+ * files and potentially troublesome .svn folders.
+ */
+ static public void copyDir(File sourceDir,
+ File targetDir) throws IOException {
+ targetDir.mkdirs();
+ String files[] = sourceDir.list();
+ for (int i = 0; i < files.length; i++) {
+ // Ignore dot files (.DS_Store), dot folders (.svn) while copying
+ if (files[i].charAt(0) == '.') continue;
+ //if (files[i].equals(".") || files[i].equals("..")) continue;
+ File source = new File(sourceDir, files[i]);
+ File target = new File(targetDir, files[i]);
+ if (source.isDirectory()) {
+ //target.mkdirs();
+ copyDir(source, target);
+ target.setLastModified(source.lastModified());
+ } else {
+ copyFile(source, target);
+ }
+ }
+ }
+
+
+ /**
+ * Remove all files in a directory and the directory itself.
+ */
+ static public void removeDir(File dir) {
+ if (dir.exists()) {
+ removeDescendants(dir);
+ if (!dir.delete()) {
+ System.err.println("Could not delete " + dir);
+ }
+ }
+ }
+
+
+ /**
+ * Recursively remove all files within a directory,
+ * used with removeDir(), or when the contents of a dir
+ * should be removed, but not the directory itself.
+ * (i.e. when cleaning temp files from lib/build)
+ */
+ static public void removeDescendants(File dir) {
+ if (!dir.exists()) return;
+
+ String files[] = dir.list();
+ for (int i = 0; i < files.length; i++) {
+ if (files[i].equals(".") || files[i].equals("..")) continue;
+ File dead = new File(dir, files[i]);
+ if (!dead.isDirectory()) {
+ if (!Preferences.getBoolean("compiler.save_build_files")) {
+ if (!dead.delete()) {
+ // temporarily disabled
+ System.err.println("Could not delete " + dead);
+ }
+ }
+ } else {
+ removeDir(dead);
+ //dead.delete();
+ }
+ }
+ }
+
+
+ /**
+ * Calculate the size of the contents of a folder.
+ * Used to determine whether sketches are empty or not.
+ * Note that the function calls itself recursively.
+ */
+ static public int calcFolderSize(File folder) {
+ int size = 0;
+
+ String files[] = folder.list();
+ // null if folder doesn't exist, happens when deleting sketch
+ if (files == null) return -1;
+
+ for (int i = 0; i < files.length; i++) {
+ if (files[i].equals(".") || (files[i].equals("..")) ||
+ files[i].equals(".DS_Store")) continue;
+ File fella = new File(folder, files[i]);
+ if (fella.isDirectory()) {
+ size += calcFolderSize(fella);
+ } else {
+ size += (int) fella.length();
+ }
+ }
+ return size;
+ }
+
+
+ /**
+ * Recursively creates a list of all files within the specified folder,
+ * and returns a list of their relative paths.
+ * Ignores any files/folders prefixed with a dot.
+ */
+ static public String[] listFiles(String path, boolean relative) {
+ return listFiles(new File(path), relative);
+ }
+
+
+ static public String[] listFiles(File folder, boolean relative) {
+ String path = folder.getAbsolutePath();
+ Vector vector = new Vector();
+ listFiles(relative ? (path + File.separator) : "", path, vector);
+ String outgoing[] = new String[vector.size()];
+ vector.copyInto(outgoing);
+ return outgoing;
+ }
+
+
+ static protected void listFiles(String basePath,
+ String path, Vector vector) {
+ File folder = new File(path);
+ String list[] = folder.list();
+ if (list == null) return;
+
+ for (int i = 0; i < list.length; i++) {
+ if (list[i].charAt(0) == '.') continue;
+
+ File file = new File(path, list[i]);
+ String newPath = file.getAbsolutePath();
+ if (newPath.startsWith(basePath)) {
+ newPath = newPath.substring(basePath.length());
+ }
+ vector.add(newPath);
+ if (file.isDirectory()) {
+ listFiles(basePath, newPath, vector);
+ }
+ }
+ }
+}
diff --git a/app/src/processing/app/Commander.java b/app/src/processing/app/Commander.java
new file mode 100644
index 000000000..88d9cb598
--- /dev/null
+++ b/app/src/processing/app/Commander.java
@@ -0,0 +1,297 @@
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+/*
+ Part of the Processing project - http://processing.org
+
+ Copyright (c) 2008 Ben Fry and Casey Reas
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+package processing.app;
+
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintStream;
+
+import processing.core.PApplet;
+
+import processing.app.debug.*;
+
+
+/**
+ * Class to handle running Processing from the command line.
+ *
+ * --help Show the help text.
+ *
+ * --sketch=<name&rt; Specify the sketch folder (required)
+ * --output=<name&rt; Specify the output folder (required and
+ * cannot be the same as the sketch folder.)
+ *
+ * --preprocess Preprocess a sketch into .java files.
+ * --build Preprocess and compile a sketch into .class files.
+ * --run Preprocess, compile, and run a sketch.
+ * --present Preprocess, compile, and run a sketch full screen.
+ *
+ * --export-applet Export an applet.
+ * --export-application Export an application.
+ * --platform Specify the platform (export to application only).
+ * Should be one of 'windows', 'macosx', or 'linux'.
+ *
+ * --preferences=<file&rt; Specify a preferences file to use (optional).
+ *
+ *
+ * To build the command line version, first build for your platform,
+ * then cd to processing/build/cmd and type 'dist.sh'. This will create a
+ * usable installation plus a zip file of the same.
+ *
+ * @author fry
+ */
+public class Commander implements RunnerListener {
+ static final String helpArg = "--help";
+ static final String preprocArg = "--preprocess";
+ static final String buildArg = "--build";
+ static final String runArg = "--run";
+ static final String presentArg = "--present";
+ static final String sketchArg = "--sketch=";
+ static final String outputArg = "--output=";
+ static final String exportAppletArg = "--export-applet";
+ static final String exportApplicationArg = "--export-application";
+ static final String platformArg = "--platform=";
+ static final String preferencesArg = "--preferences=";
+
+ static final int HELP = -1;
+ static final int PREPROCESS = 0;
+ static final int BUILD = 1;
+ static final int RUN = 2;
+ static final int PRESENT = 3;
+ static final int EXPORT_APPLET = 4;
+ static final int EXPORT_APPLICATION = 5;
+
+ Sketch sketch;
+
+
+ static public void main(String[] args) {
+ // init the platform so that prefs and other native code is ready to go
+ Base.initPlatform();
+ // make sure a full JDK is installed
+ Base.initRequirements();
+ // run static initialization that grabs all the prefs
+ //Preferences.init(null);
+ // launch command line handler
+ new Commander(args);
+ }
+
+
+ public Commander(String[] args) {
+ String sketchFolder = null;
+ String pdePath = null; // path to the .pde file
+ String outputPath = null;
+ String preferencesPath = null;
+ int platformIndex = PApplet.platform; // default to this platform
+ int mode = HELP;
+
+ for (String arg : args) {
+ if (arg.length() == 0) {
+ // ignore it, just the crappy shell script
+
+ } else if (arg.equals(helpArg)) {
+ // mode already set to HELP
+
+ } else if (arg.equals(buildArg)) {
+ mode = BUILD;
+
+ } else if (arg.equals(runArg)) {
+ mode = RUN;
+
+ } else if (arg.equals(presentArg)) {
+ mode = PRESENT;
+
+ } else if (arg.equals(preprocArg)) {
+ mode = PREPROCESS;
+
+ } else if (arg.equals(exportAppletArg)) {
+ mode = EXPORT_APPLET;
+
+ } else if (arg.equals(exportApplicationArg)) {
+ mode = EXPORT_APPLICATION;
+
+ } else if (arg.startsWith(platformArg)) {
+ String platformStr = arg.substring(platformArg.length());
+ platformIndex = Base.getPlatformIndex(platformStr);
+ if (platformIndex == -1) {
+ complainAndQuit(platformStr + " should instead be " +
+ "'windows', 'macosx', or 'linux'.");
+ }
+ } else if (arg.startsWith(sketchArg)) {
+ sketchFolder = arg.substring(sketchArg.length());
+ File sketchy = new File(sketchFolder);
+ File pdeFile = new File(sketchy, sketchy.getName() + ".pde");
+ pdePath = pdeFile.getAbsolutePath();
+
+ } else if (arg.startsWith(outputArg)) {
+ outputPath = arg.substring(outputArg.length());
+
+ } else {
+ complainAndQuit("I don't know anything about " + arg + ".");
+ }
+ }
+
+ if ((outputPath == null) &&
+ (mode == PREPROCESS || mode == BUILD ||
+ mode == RUN || mode == PRESENT)) {
+ complainAndQuit("An output path must be specified when using " +
+ preprocArg + ", " + buildArg + ", " +
+ runArg + ", or " + presentArg + ".");
+ }
+
+ if (mode == HELP) {
+ printCommandLine(System.out);
+ System.exit(0);
+ }
+
+ // --present --platform=windows "--sketch=/Applications/Processing 0148/examples/Basics/Arrays/Array" --output=test-build
+
+ File outputFolder = new File(outputPath);
+ if (!outputFolder.exists()) {
+ if (!outputFolder.mkdirs()) {
+ complainAndQuit("Could not create the output folder.");
+ }
+ }
+
+ // run static initialization that grabs all the prefs
+ // (also pass in a prefs path if that was specified)
+ Preferences.init(preferencesPath);
+
+ if (sketchFolder == null) {
+ complainAndQuit("No sketch path specified.");
+
+ } else if (outputPath.equals(pdePath)) {
+ complainAndQuit("The sketch path and output path cannot be identical.");
+
+ } else if (!pdePath.toLowerCase().endsWith(".pde")) {
+ complainAndQuit("Sketch path must point to the main .pde file.");
+
+ } else {
+ //Sketch sketch = null;
+ boolean success = false;
+
+ try {
+ sketch = new Sketch(null, pdePath);
+ if (mode == PREPROCESS) {
+ success = sketch.preprocess(outputPath) != null;
+
+ } else if (mode == BUILD) {
+ success = sketch.build(outputPath) != null;
+
+ } else if (mode == RUN || mode == PRESENT) {
+ String className = sketch.build(outputPath);
+ if (className != null) {
+ success = true;
+ Runner runner =
+ new Runner(sketch, className, mode == PRESENT, this);
+ runner.launch();
+
+ } else {
+ success = false;
+ }
+
+ } else if (mode == EXPORT_APPLET) {
+ if (outputPath != null) {
+ success = sketch.exportApplet(outputPath);
+ } else {
+ String target = sketchFolder + File.separatorChar + "applet";
+ success = sketch.exportApplet(target);
+ }
+ } else if (mode == EXPORT_APPLICATION) {
+ if (outputPath != null) {
+ success = sketch.exportApplication(outputPath, platformIndex);
+ } else {
+ //String sketchFolder =
+ // pdePath.substring(0, pdePath.lastIndexOf(File.separatorChar));
+ outputPath =
+ sketchFolder + File.separatorChar +
+ "application." + Base.getPlatformName(platformIndex);
+ success = sketch.exportApplication(outputPath, platformIndex);
+ }
+ }
+ System.exit(success ? 0 : 1);
+
+ } catch (RunnerException re) {
+ statusError(re);
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+ }
+ }
+
+
+ public void statusError(String message) {
+ System.err.println(message);
+ }
+
+
+ public void statusError(Exception exception) {
+ if (exception instanceof RunnerException) {
+ RunnerException re = (RunnerException) exception;
+
+ // format the runner exception like emacs
+ //blah.java:2:10:2:13: Syntax Error: This is a big error message
+ String filename = sketch.getCode(re.getCodeIndex()).getFileName();
+ int line = re.getCodeLine();
+ int column = re.getCodeColumn();
+ if (column == -1) column = 0;
+ // TODO if column not specified, should just select the whole line.
+ System.err.println(filename + ":" +
+ line + ":" + column + ":" +
+ line + ":" + column + ":" + " " + re.getMessage());
+ } else {
+ exception.printStackTrace();
+ }
+ }
+
+
+ static void complainAndQuit(String lastWords) {
+ printCommandLine(System.err);
+ System.err.println(lastWords);
+ System.exit(1);
+ }
+
+
+ static void printCommandLine(PrintStream out) {
+ out.println("Processing " + Base.VERSION_NAME + " rocks the console.");
+ out.println();
+ out.println("--help Show this help text.");
+ out.println();
+ out.println("--sketch= Specify the sketch folder (required)");
+ out.println("--output= Specify the output folder (required and");
+ out.println(" cannot be the same as the sketch folder.)");
+ out.println();
+ out.println("--preprocess Preprocess a sketch into .java files.");
+ out.println("--build Preprocess and compile a sketch into .class files.");
+ out.println("--run Preprocess, compile, and run a sketch.");
+ out.println("--present Preprocess, compile, and run a sketch full screen.");
+ out.println();
+ out.println("--export-applet Export an applet.");
+ out.println("--export-application Export an application.");
+ out.println("--platform Specify the platform (export to application only).");
+ out.println(" Should be one of 'windows', 'macosx', or 'linux'.");
+ out.println();
+ out.println("--preferences= Specify a preferences file to use (optional).");
+ }
+}
\ No newline at end of file
diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java
new file mode 100644
index 000000000..a52b55b69
--- /dev/null
+++ b/app/src/processing/app/Editor.java
@@ -0,0 +1,2301 @@
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+/*
+ Part of the Processing project - http://processing.org
+
+ Copyright (c) 2004-08 Ben Fry and Casey Reas
+ Copyright (c) 2001-04 Massachusetts Institute of Technology
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+package processing.app;
+
+import processing.app.debug.*;
+import processing.app.syntax.*;
+import processing.app.tools.*;
+import processing.core.*;
+
+import java.awt.*;
+import java.awt.datatransfer.*;
+import java.awt.event.*;
+import java.awt.print.*;
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import java.util.zip.*;
+
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.text.*;
+import javax.swing.undo.*;
+
+
+/**
+ * Main editor panel for the Processing Development Environment.
+ */
+public class Editor extends JFrame implements RunnerListener {
+
+ Base base;
+
+ // otherwise, if the window is resized with the message label
+ // set to blank, it's preferredSize() will be fukered
+ static protected final String EMPTY =
+ " " +
+ " " +
+ " ";
+
+ /** Command on Mac OS X, Ctrl on Windows and Linux */
+ static final int SHORTCUT_KEY_MASK =
+ Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
+ /** Command-W on Mac OS X, Ctrl-W on Windows and Linux */
+ static final KeyStroke WINDOW_CLOSE_KEYSTROKE =
+ KeyStroke.getKeyStroke('W', SHORTCUT_KEY_MASK);
+ /** Command-Option on Mac OS X, Ctrl-Alt on Windows and Linux */
+ static final int SHORTCUT_ALT_KEY_MASK = ActionEvent.ALT_MASK |
+ Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
+
+ /**
+ * true if this file has not yet been given a name by the user
+ */
+ boolean untitled;
+
+ PageFormat pageFormat;
+ PrinterJob printerJob;
+
+ // file and sketch menus for re-inserting items
+ JMenu fileMenu;
+ JMenu sketchMenu;
+
+ EditorToolbar toolbar;
+ // these menus are shared so that they needn't be rebuilt for all windows
+ // each time a sketch is created, renamed, or moved.
+ static JMenu toolbarMenu;
+ static JMenu sketchbookMenu;
+ static JMenu examplesMenu;
+ static JMenu importMenu;
+
+ EditorHeader header;
+ EditorStatus status;
+ EditorConsole console;
+
+ JSplitPane splitPane;
+ JPanel consolePanel;
+
+ JLabel lineNumberComponent;
+
+ // currently opened program
+ Sketch sketch;
+
+ EditorLineStatus lineStatus;
+
+ JEditTextArea textarea;
+ EditorListener listener;
+
+ // runtime information and window placement
+ Point sketchWindowLocation;
+ Runner runtime;
+
+ JMenuItem exportAppItem;
+ JMenuItem saveMenuItem;
+ JMenuItem saveAsMenuItem;
+
+ boolean running;
+ boolean presenting;
+
+ // undo fellers
+ JMenuItem undoItem, redoItem;
+ protected UndoAction undoAction;
+ protected RedoAction redoAction;
+ UndoManager undo;
+ // used internally, and only briefly
+ CompoundEdit compoundEdit;
+
+ FindReplace find;
+
+
+ public Editor(Base ibase, String path, int[] location) {
+ super("Processing");
+ this.base = ibase;
+
+ Base.setIcon(this);
+
+ // add listener to handle window close box hit event
+ addWindowListener(new WindowAdapter() {
+ public void windowClosing(WindowEvent e) {
+ base.handleClose(Editor.this);
+ }
+ });
+ // don't close the window when clicked, the app will take care
+ // of that via the handleQuitInternal() methods
+ // http://dev.processing.org/bugs/show_bug.cgi?id=440
+ setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
+
+ // When bringing a window to front, let the Base know
+ addWindowListener(new WindowAdapter() {
+ public void windowActivated(WindowEvent e) {
+ base.handleActivated(Editor.this);
+
+ // re-add the sub-menus that are shared by all windows
+ fileMenu.insert(sketchbookMenu, 2);
+ fileMenu.insert(examplesMenu, 3);
+ sketchMenu.insert(importMenu, 4);
+ }
+ });
+
+ //PdeKeywords keywords = new PdeKeywords();
+ //sketchbook = new Sketchbook(this);
+
+ buildMenuBar();
+
+ // For rev 0120, placing things inside a JPanel
+ Container contentPain = getContentPane();
+ contentPain.setLayout(new BorderLayout());
+ JPanel pain = new JPanel();
+ pain.setLayout(new BorderLayout());
+ contentPain.add(pain, BorderLayout.CENTER);
+
+ Box box = Box.createVerticalBox();
+ Box upper = Box.createVerticalBox();
+
+ if (toolbarMenu == null) {
+ toolbarMenu = new JMenu();
+ base.rebuildToolbarMenu(toolbarMenu);
+ }
+ toolbar = new EditorToolbar(this, toolbarMenu);
+ upper.add(toolbar);
+
+ header = new EditorHeader(this);
+ upper.add(header);
+
+ textarea = new JEditTextArea(new PdeTextAreaDefaults());
+ textarea.setRightClickPopup(new TextAreaPopup());
+ textarea.setHorizontalOffset(6);
+
+ // assemble console panel, consisting of status area and the console itself
+ consolePanel = new JPanel();
+ consolePanel.setLayout(new BorderLayout());
+
+ status = new EditorStatus(this);
+ consolePanel.add(status, BorderLayout.NORTH);
+
+ console = new EditorConsole(this);
+ // windows puts an ugly border on this guy
+ console.setBorder(null);
+ consolePanel.add(console, BorderLayout.CENTER);
+
+ lineStatus = new EditorLineStatus(textarea);
+ consolePanel.add(lineStatus, BorderLayout.SOUTH);
+
+ upper.add(textarea);
+ splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
+ upper, consolePanel);
+
+ splitPane.setOneTouchExpandable(true);
+ // repaint child panes while resizing
+ splitPane.setContinuousLayout(true);
+ // if window increases in size, give all of increase to
+ // the textarea in the uppper pane
+ splitPane.setResizeWeight(1D);
+
+ // to fix ugliness.. normally macosx java 1.3 puts an
+ // ugly white border around this object, so turn it off.
+ splitPane.setBorder(null);
+
+ // the default size on windows is too small and kinda ugly
+ int dividerSize = Preferences.getInteger("editor.divider.size");
+ if (dividerSize != 0) {
+ splitPane.setDividerSize(dividerSize);
+ }
+
+ splitPane.setMinimumSize(new Dimension(600, 400));
+ box.add(splitPane);
+
+ // hopefully these are no longer needed w/ swing
+ // (har har har.. that was wishful thinking)
+ listener = new EditorListener(this, textarea);
+ pain.add(box);
+
+ pain.setTransferHandler(new TransferHandler() {
+
+ public boolean canImport(JComponent dest, DataFlavor[] flavors) {
+ return true;
+ }
+
+ public boolean importData(JComponent src, Transferable transferable) {
+ int successful = 0;
+
+ try {
+ DataFlavor uriListFlavor =
+ new DataFlavor("text/uri-list;class=java.lang.String");
+
+ if (transferable.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
+ java.util.List list = (java.util.List)
+ transferable.getTransferData(DataFlavor.javaFileListFlavor);
+ for (int i = 0; i < list.size(); i++) {
+ File file = (File) list.get(i);
+ if (sketch.addFile(file)) {
+ successful++;
+ }
+ }
+ } else if (transferable.isDataFlavorSupported(uriListFlavor)) {
+ //System.out.println("uri list");
+ String data = (String)transferable.getTransferData(uriListFlavor);
+ String[] pieces = PApplet.splitTokens(data, "\r\n");
+ //PApplet.println(pieces);
+ for (int i = 0; i < pieces.length; i++) {
+ if (pieces[i].startsWith("#")) continue;
+
+ String path = null;
+ if (pieces[i].startsWith("file:///")) {
+ path = pieces[i].substring(7);
+ } else if (pieces[i].startsWith("file:/")) {
+ path = pieces[i].substring(5);
+ }
+ if (sketch.addFile(new File(path))) {
+ successful++;
+ }
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+
+ if (successful == 0) {
+ statusError("No files were added to the sketch.");
+
+ } else if (successful == 1) {
+ statusNotice("One file added to the sketch.");
+
+ } else {
+ statusNotice(successful + " files added to the sketch.");
+ }
+ return true;
+ }
+ });
+
+// System.out.println("t1");
+
+ // Finish preparing Editor (formerly found in Base)
+ pack();
+
+// System.out.println("t2");
+
+ // Set the window bounds and the divider location before setting it visible
+ setPlacement(location);
+
+// System.out.println("t3");
+
+ // Bring back the general options for the editor
+ applyPreferences();
+
+// System.out.println("t4");
+
+ // Open the document that was passed in
+ boolean loaded = handleOpenInternal(path);
+ if (!loaded) sketch = null;
+
+// System.out.println("t5");
+
+ // All set, now show the window
+ //setVisible(true);
+ }
+
+
+ protected void setPlacement(int[] location) {
+ setBounds(location[0], location[1], location[2], location[3]);
+ if (location[4] != 0) {
+ splitPane.setDividerLocation(location[4]);
+ }
+ }
+
+
+ protected int[] getPlacement() {
+ int[] location = new int[5];
+
+ // Get the dimensions of the Frame
+ Rectangle bounds = getBounds();
+ location[0] = bounds.x;
+ location[1] = bounds.y;
+ location[2] = bounds.width;
+ location[3] = bounds.height;
+
+ // Get the current placement of the divider
+ location[4] = splitPane.getDividerLocation();
+
+ return location;
+ }
+
+
+ /**
+ * Hack for #@#)$(* Mac OS X 10.2.
+ *
+ * This appears to only be required on OS X 10.2, and is not
+ * even being called on later versions of OS X or Windows.
+ */
+ public Dimension getMinimumSize() {
+ //System.out.println("getting minimum size");
+ return new Dimension(500, 550);
+ }
+
+
+ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+
+
+ /**
+ * Read and apply new values from the preferences, either because
+ * the app is just starting up, or the user just finished messing
+ * with things in the Preferences window.
+ */
+ protected void applyPreferences() {
+
+ // apply the setting for 'use external editor'
+ boolean external = Preferences.getBoolean("editor.external");
+
+ textarea.setEditable(!external);
+ saveMenuItem.setEnabled(!external);
+ saveAsMenuItem.setEnabled(!external);
+
+ TextAreaPainter painter = textarea.getPainter();
+ if (external) {
+ // disable line highlight and turn off the caret when disabling
+ Color color = Theme.getColor("editor.external.bgcolor");
+ painter.setBackground(color);
+ painter.setLineHighlightEnabled(false);
+ textarea.setCaretVisible(false);
+
+ } else {
+ Color color = Theme.getColor("editor.bgcolor");
+ painter.setBackground(color);
+ boolean highlight = Preferences.getBoolean("editor.linehighlight");
+ painter.setLineHighlightEnabled(highlight);
+ textarea.setCaretVisible(true);
+ }
+
+ // apply changes to the font size for the editor
+ //TextAreaPainter painter = textarea.getPainter();
+ painter.setFont(Preferences.getFont("editor.font"));
+ //Font font = painter.getFont();
+ //textarea.getPainter().setFont(new Font("Courier", Font.PLAIN, 36));
+
+ // in case tab expansion stuff has changed
+ listener.applyPreferences();
+
+ // in case moved to a new location
+ // For 0125, changing to async version (to be implemented later)
+ //sketchbook.rebuildMenus();
+ // For 0126, moved into Base, which will notify all editors.
+ //base.rebuildMenusAsync();
+ }
+
+
+ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+
+
+ protected void buildMenuBar() {
+ JMenuBar menubar = new JMenuBar();
+ menubar = new JMenuBar();
+ menubar.add(buildFileMenu());
+ menubar.add(buildEditMenu());
+ menubar.add(buildSketchMenu());
+ menubar.add(buildToolsMenu());
+ menubar.add(buildHelpMenu());
+ setJMenuBar(menubar);
+ }
+
+
+ protected JMenu buildFileMenu() {
+ JMenuItem item;
+ fileMenu = new JMenu("File");
+
+ item = newJMenuItem("New", 'N');
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ base.handleNew();
+ }
+ });
+ fileMenu.add(item);
+
+ item = Editor.newJMenuItem("Open...", 'O');
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ base.handleOpenPrompt();
+ }
+ });
+ fileMenu.add(item);
+
+ if (sketchbookMenu == null) {
+ sketchbookMenu = new JMenu("Sketchbook");
+ base.rebuildSketchbookMenu(sketchbookMenu);
+ }
+ fileMenu.add(sketchbookMenu);
+
+ if (examplesMenu == null) {
+ examplesMenu = new JMenu("Examples");
+ base.rebuildExamplesMenu(examplesMenu);
+ }
+ fileMenu.add(examplesMenu);
+
+ item = Editor.newJMenuItem("Close", 'W');
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ base.handleClose(Editor.this);
+ }
+ });
+ fileMenu.add(item);
+
+ saveMenuItem = newJMenuItem("Save", 'S');
+ saveMenuItem.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ handleSave(false);
+ }
+ });
+ fileMenu.add(saveMenuItem);
+
+ saveAsMenuItem = newJMenuItemShift("Save As...", 'S');
+ saveAsMenuItem.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ handleSaveAs();
+ }
+ });
+ fileMenu.add(saveAsMenuItem);
+
+ item = newJMenuItem("Export", 'E');
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ handleExport();
+ }
+ });
+ fileMenu.add(item);
+
+ exportAppItem = newJMenuItemShift("Export Application", 'E');
+ exportAppItem.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ //buttons.activate(EditorButtons.EXPORT);
+ //SwingUtilities.invokeLater(new Runnable() {
+ //public void run() {
+ handleExportApplication();
+ //}});
+ }
+ });
+ fileMenu.add(exportAppItem);
+
+ fileMenu.addSeparator();
+
+ item = newJMenuItemShift("Page Setup", 'P');
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ handlePageSetup();
+ }
+ });
+ fileMenu.add(item);
+
+ item = newJMenuItem("Print", 'P');
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ handlePrint();
+ }
+ });
+ fileMenu.add(item);
+
+ // macosx already has its own preferences and quit menu
+ if (!Base.isMacOS()) {
+ fileMenu.addSeparator();
+
+ item = newJMenuItem("Preferences", ',');
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ base.handlePrefs();
+ }
+ });
+ fileMenu.add(item);
+
+ fileMenu.addSeparator();
+
+ item = newJMenuItem("Quit", 'Q');
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ base.handleQuit();
+ }
+ });
+ fileMenu.add(item);
+ }
+ return fileMenu;
+ }
+
+
+ protected JMenu buildSketchMenu() {
+ JMenuItem item;
+ sketchMenu = new JMenu("Sketch");
+
+ item = newJMenuItem("Run", 'R');
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ handleRun(false);
+ }
+ });
+ sketchMenu.add(item);
+
+ item = newJMenuItemShift("Present", 'R');
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ handleRun(true);
+ }
+ });
+ sketchMenu.add(item);
+
+ item = new JMenuItem("Stop");
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ handleStop();
+ }
+ });
+ sketchMenu.add(item);
+
+ sketchMenu.addSeparator();
+
+ if (importMenu == null) {
+ importMenu = new JMenu("Import Library...");
+ base.rebuildImportMenu(importMenu);
+ }
+ sketchMenu.add(importMenu);
+
+ item = newJMenuItem("Show Sketch Folder", 'K');
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ Base.openFolder(sketch.getFolder());
+ }
+ });
+ sketchMenu.add(item);
+ item.setEnabled(Base.openFolderAvailable());
+
+ item = new JMenuItem("Add File...");
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ sketch.handleAddFile();
+ }
+ });
+ sketchMenu.add(item);
+
+ return sketchMenu;
+ }
+
+
+ protected JMenu buildToolsMenu() {
+ JMenu menu = new JMenu("Tools");
+
+ addInternalTools(menu);
+ addTools(menu, Base.getToolsFolder());
+ File sketchbookTools = new File(Base.getSketchbookFolder(), "tools");
+ addTools(menu, sketchbookTools);
+
+ return menu;
+ }
+
+
+ protected void addTools(JMenu menu, File sourceFolder) {
+ HashMap toolItems = new HashMap();
+
+ File[] folders = sourceFolder.listFiles(new FileFilter() {
+ public boolean accept(File folder) {
+ if (folder.isDirectory()) {
+ //System.out.println("checking " + folder);
+ File subfolder = new File(folder, "tool");
+ return subfolder.exists();
+ }
+ return false;
+ }
+ });
+
+ if (folders == null || folders.length == 0) {
+ return;
+ }
+
+ for (int i = 0; i < folders.length; i++) {
+ File toolDirectory = new File(folders[i], "tool");
+
+ try {
+ // add dir to classpath for .classes
+ //urlList.add(toolDirectory.toURL());
+
+ // add .jar files to classpath
+ File[] archives = toolDirectory.listFiles(new FilenameFilter() {
+ public boolean accept(File dir, String name) {
+ return (name.toLowerCase().endsWith(".jar") ||
+ name.toLowerCase().endsWith(".zip"));
+ }
+ });
+
+ URL[] urlList = new URL[archives.length];
+ for (int j = 0; j < urlList.length; j++) {
+ urlList[j] = archives[j].toURL();
+ }
+ URLClassLoader loader = new URLClassLoader(urlList);
+
+ String className = null;
+ for (int j = 0; j < archives.length; j++) {
+ className = findClassInZipFile(folders[i].getName(), archives[j]);
+ if (className != null) break;
+ }
+
+ /*
+ // Alternatively, could use manifest files with special attributes:
+ // http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html
+ // Example code for loading from a manifest file:
+ // http://forums.sun.com/thread.jspa?messageID=3791501
+ File infoFile = new File(toolDirectory, "tool.txt");
+ if (!infoFile.exists()) continue;
+
+ String[] info = PApplet.loadStrings(infoFile);
+ //Main-Class: org.poo.shoe.AwesomerTool
+ //String className = folders[i].getName();
+ String className = null;
+ for (int k = 0; k < info.length; k++) {
+ if (info[k].startsWith(";")) continue;
+
+ String[] pieces = PApplet.splitTokens(info[k], ": ");
+ if (pieces.length == 2) {
+ if (pieces[0].equals("Main-Class")) {
+ className = pieces[1];
+ }
+ }
+ }
+ */
+ // If no class name found, just move on.
+ if (className == null) continue;
+
+ Class toolClass = Class.forName(className, true, loader);
+ final Tool tool = (Tool) toolClass.newInstance();
+
+ tool.init(Editor.this);
+
+ String title = tool.getMenuTitle();
+ JMenuItem item = new JMenuItem(title);
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ SwingUtilities.invokeLater(tool);
+ }
+ });
+ //menu.add(item);
+ toolItems.put(title, item);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ ArrayList toolList = new ArrayList(toolItems.keySet());
+ if (toolList.size() == 0) return;
+
+ menu.addSeparator();
+ Collections.sort(toolList);
+ for (String title : toolList) {
+ menu.add((JMenuItem) toolItems.get(title));
+ }
+ }
+
+
+ protected String findClassInZipFile(String base, File file) {
+ // Class file to search for
+ String classFileName = "/" + base + ".class";
+
+ try {
+ ZipFile zipFile = new ZipFile(file);
+ Enumeration entries = zipFile.entries();
+ while (entries.hasMoreElements()) {
+ ZipEntry entry = (ZipEntry) entries.nextElement();
+
+ if (!entry.isDirectory()) {
+ String name = entry.getName();
+ //System.out.println("entry: " + name);
+
+ if (name.endsWith(classFileName)) {
+ //int slash = name.lastIndexOf('/');
+ //String packageName = (slash == -1) ? "" : name.substring(0, slash);
+ // Remove .class and convert slashes to periods.
+ return name.substring(0, name.length() - 6).replace('/', '.');
+ }
+ }
+ }
+ } catch (IOException e) {
+ //System.err.println("Ignoring " + filename + " (" + e.getMessage() + ")");
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+
+ protected JMenuItem createToolMenuItem(String className) {
+ try {
+ Class toolClass = Class.forName(className);
+ final Tool tool = (Tool) toolClass.newInstance();
+
+ JMenuItem item = new JMenuItem(tool.getMenuTitle());
+
+ tool.init(Editor.this);
+
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ SwingUtilities.invokeLater(tool);
+ }
+ });
+ return item;
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+
+ protected JMenu addInternalTools(JMenu menu) {
+ JMenuItem item;
+
+ item = createToolMenuItem("processing.app.tools.AutoFormat");
+ int modifiers = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
+ item.setAccelerator(KeyStroke.getKeyStroke('T', modifiers));
+ menu.add(item);
+
+ menu.add(createToolMenuItem("processing.app.tools.CreateFont"));
+ menu.add(createToolMenuItem("processing.app.tools.ColorSelector"));
+ menu.add(createToolMenuItem("processing.app.tools.Archiver"));
+ menu.add(createToolMenuItem("processing.app.tools.FixEncoding"));
+
+ return menu;
+ }
+
+
+ protected JMenu buildHelpMenu() {
+ JMenu menu = new JMenu("Help");
+ JMenuItem item;
+
+ /*
+ // testing internal web server to serve up docs from a zip file
+ item = new JMenuItem("Web Server Test");
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ //WebServer ws = new WebServer();
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ try {
+ int port = WebServer.launch("/Users/fry/coconut/processing/build/shared/reference.zip");
+ Base.openURL("http://127.0.0.1:" + port + "/reference/setup_.html");
+
+ } catch (IOException e1) {
+ e1.printStackTrace();
+ }
+ }
+ });
+ }
+ });
+ menu.add(item);
+ */
+
+ /*
+ item = new JMenuItem("Browser Test");
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ //Base.openURL("http://processing.org/learning/gettingstarted/");
+ //JFrame browserFrame = new JFrame("Browser");
+ BrowserStartup bs = new BrowserStartup("jar:file:/Users/fry/coconut/processing/build/shared/reference.zip!/reference/setup_.html");
+ bs.initUI();
+ bs.launch();
+ }
+ });
+ menu.add(item);
+ */
+
+ item = new JMenuItem("Getting Started");
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ Base.openURL("http://processing.org/learning/gettingstarted/");
+ }
+ });
+ menu.add(item);
+
+ item = new JMenuItem("Environment");
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ Base.showEnvironment();
+ }
+ });
+ menu.add(item);
+
+ item = new JMenuItem("Troubleshooting");
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ Base.showTroubleshooting();
+ }
+ });
+ menu.add(item);
+
+ item = new JMenuItem("Reference");
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ Base.showReference();
+ }
+ });
+ menu.add(item);
+
+ item = newJMenuItemShift("Find in Reference", 'F');
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ if (textarea.isSelectionActive()) {
+ handleFindReference();
+ }
+ }
+ });
+ menu.add(item);
+
+ item = new JMenuItem("Frequently Asked Questions");
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ Base.openURL("http://processing.org/faq.html");
+ }
+ });
+ menu.add(item);
+
+ item = newJMenuItem("Visit Processing.org", '5');
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ Base.openURL("http://processing.org/");
+ }
+ });
+ menu.add(item);
+
+ // macosx already has its own about menu
+ if (!Base.isMacOS()) {
+ menu.addSeparator();
+ item = new JMenuItem("About Processing");
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ base.handleAbout();
+ }
+ });
+ menu.add(item);
+ }
+
+ return menu;
+ }
+
+
+ protected JMenu buildEditMenu() {
+ JMenu menu = new JMenu("Edit");
+ JMenuItem item;
+
+ undoItem = newJMenuItem("Undo", 'Z');
+ undoItem.addActionListener(undoAction = new UndoAction());
+ menu.add(undoItem);
+
+ redoItem = newJMenuItem("Redo", 'Y');
+ redoItem.addActionListener(redoAction = new RedoAction());
+ menu.add(redoItem);
+
+ menu.addSeparator();
+
+ // TODO "cut" and "copy" should really only be enabled
+ // if some text is currently selected
+ item = newJMenuItem("Cut", 'X');
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ handleCut();
+ }
+ });
+ menu.add(item);
+
+ item = newJMenuItem("Copy", 'C');
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ textarea.copy();
+ }
+ });
+ menu.add(item);
+
+ item = newJMenuItemShift("Copy for Discourse", 'C');
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+// SwingUtilities.invokeLater(new Runnable() {
+// public void run() {
+ new DiscourseFormat(Editor.this).show();
+// }
+// });
+ }
+ });
+ menu.add(item);
+
+ item = newJMenuItem("Paste", 'V');
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ textarea.paste();
+ sketch.setModified(true);
+ }
+ });
+ menu.add(item);
+
+ item = newJMenuItem("Select All", 'A');
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ textarea.selectAll();
+ }
+ });
+ menu.add(item);
+
+ menu.addSeparator();
+
+ item = newJMenuItem("Comment/Uncomment", '/');
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ handleCommentUncomment();
+ }
+ });
+ menu.add(item);
+
+ item = newJMenuItem("Increase Indent", ']');
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ handleIndentOutdent(true);
+ }
+ });
+ menu.add(item);
+
+ item = newJMenuItem("Decrease Indent", '[');
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ handleIndentOutdent(false);
+ }
+ });
+ menu.add(item);
+
+ menu.addSeparator();
+
+ item = newJMenuItem("Find...", 'F');
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ if (find == null) {
+ find = new FindReplace(Editor.this);
+ }
+ //new FindReplace(Editor.this).show();
+ find.setVisible(true);
+ //find.setVisible(true);
+ }
+ });
+ menu.add(item);
+
+ // TODO find next should only be enabled after a
+ // search has actually taken place
+ item = newJMenuItem("Find Next", 'G');
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ if (find != null) {
+ //find.find(true);
+ //FindReplace find = new FindReplace(Editor.this); //.show();
+ find.find(true);
+ }
+ }
+ });
+ menu.add(item);
+
+ return menu;
+ }
+
+
+ /**
+ * A software engineer, somewhere, needs to have his abstraction
+ * taken away. In some countries they jail or beat people for writing
+ * the sort of API that would require a five line helper function
+ * just to set the command key for a menu item.
+ */
+ static public JMenuItem newJMenuItem(String title, int what) {
+ JMenuItem menuItem = new JMenuItem(title);
+ int modifiers = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
+ menuItem.setAccelerator(KeyStroke.getKeyStroke(what, modifiers));
+ return menuItem;
+ }
+
+
+ /**
+ * Like newJMenuItem() but adds shift as a modifier for the key command.
+ */
+ static public JMenuItem newJMenuItemShift(String title, int what) {
+ JMenuItem menuItem = new JMenuItem(title);
+ int modifiers = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
+ modifiers |= ActionEvent.SHIFT_MASK;
+ menuItem.setAccelerator(KeyStroke.getKeyStroke(what, modifiers));
+ return menuItem;
+ }
+
+
+ /**
+ * Same as newJMenuItem(), but adds the ALT (on Linux and Windows)
+ * or OPTION (on Mac OS X) key as a modifier.
+ */
+ static public JMenuItem newJMenuItemAlt(String title, int what) {
+ JMenuItem menuItem = new JMenuItem(title);
+ //int modifiers = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
+ //menuItem.setAccelerator(KeyStroke.getKeyStroke(what, modifiers));
+ menuItem.setAccelerator(KeyStroke.getKeyStroke(what, SHORTCUT_ALT_KEY_MASK));
+ return menuItem;
+ }
+
+
+ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+
+
+ class UndoAction extends AbstractAction {
+ public UndoAction() {
+ super("Undo");
+ this.setEnabled(false);
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ try {
+ undo.undo();
+ } catch (CannotUndoException ex) {
+ //System.out.println("Unable to undo: " + ex);
+ //ex.printStackTrace();
+ }
+ updateUndoState();
+ redoAction.updateRedoState();
+ }
+
+ protected void updateUndoState() {
+ if (undo.canUndo()) {
+ this.setEnabled(true);
+ undoItem.setEnabled(true);
+ undoItem.setText(undo.getUndoPresentationName());
+ putValue(Action.NAME, undo.getUndoPresentationName());
+ if (sketch != null) {
+ sketch.setModified(true); // 0107
+ }
+ } else {
+ this.setEnabled(false);
+ undoItem.setEnabled(false);
+ undoItem.setText("Undo");
+ putValue(Action.NAME, "Undo");
+ if (sketch != null) {
+ sketch.setModified(false); // 0107
+ }
+ }
+ }
+ }
+
+
+ class RedoAction extends AbstractAction {
+ public RedoAction() {
+ super("Redo");
+ this.setEnabled(false);
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ try {
+ undo.redo();
+ } catch (CannotRedoException ex) {
+ //System.out.println("Unable to redo: " + ex);
+ //ex.printStackTrace();
+ }
+ updateRedoState();
+ undoAction.updateUndoState();
+ }
+
+ protected void updateRedoState() {
+ if (undo.canRedo()) {
+ redoItem.setEnabled(true);
+ redoItem.setText(undo.getRedoPresentationName());
+ putValue(Action.NAME, undo.getRedoPresentationName());
+ } else {
+ this.setEnabled(false);
+ redoItem.setEnabled(false);
+ redoItem.setText("Redo");
+ putValue(Action.NAME, "Redo");
+ }
+ }
+ }
+
+
+ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+
+
+ /**
+ * Gets the current sketch object.
+ */
+ public Sketch getSketch() {
+ return sketch;
+ }
+
+
+ /**
+ * Get the JEditTextArea object for use (not recommended). This should only
+ * be used in obscure cases that really need to hack the internals of the
+ * JEditTextArea. Most tools should only interface via the get/set functions
+ * found in this class. This will maintain compatibility with future releases,
+ * which will not use JEditTextArea.
+ */
+ public JEditTextArea getTextArea() {
+ return textarea;
+ }
+
+
+ /**
+ * Get the contents of the current buffer. Used by the Sketch class.
+ */
+ public String getText() {
+ return textarea.getText();
+ }
+
+
+ /**
+ * Get a range of text from the current buffer.
+ */
+ public String getText(int start, int stop) {
+ return textarea.getText(start, stop - start);
+ }
+
+
+ /**
+ * Replace the entire contents of the front-most tab.
+ */
+ public void setText(String what) {
+ startCompoundEdit();
+ textarea.setText(what);
+ stopCompoundEdit();
+ }
+
+
+ public void insertText(String what) {
+ startCompoundEdit();
+ int caret = getCaretOffset();
+ setSelection(caret, caret);
+ textarea.setSelectedText(what);
+ stopCompoundEdit();
+ }
+
+
+ /**
+ * Called to update the text but not switch to a different set of code
+ * (which would affect the undo manager).
+ */
+// public void setText2(String what, int start, int stop) {
+// beginCompoundEdit();
+// textarea.setText(what);
+// endCompoundEdit();
+//
+// // make sure that a tool isn't asking for a bad location
+// start = Math.max(0, Math.min(start, textarea.getDocumentLength()));
+// stop = Math.max(0, Math.min(start, textarea.getDocumentLength()));
+// textarea.select(start, stop);
+//
+// textarea.requestFocus(); // get the caret blinking
+// }
+
+
+ public String getSelectedText() {
+ return textarea.getSelectedText();
+ }
+
+
+ public void setSelectedText(String what) {
+ textarea.setSelectedText(what);
+ }
+
+
+ public void setSelection(int start, int stop) {
+ // make sure that a tool isn't asking for a bad location
+ start = PApplet.constrain(start, 0, textarea.getDocumentLength());
+ stop = PApplet.constrain(stop, 0, textarea.getDocumentLength());
+
+ textarea.select(start, stop);
+ }
+
+
+ /**
+ * Get the position (character offset) of the caret. With text selected,
+ * this will be the last character actually selected, no matter the direction
+ * of the selection. That is, if the user clicks and drags to select lines
+ * 7 up to 4, then the caret position will be somewhere on line four.
+ */
+ public int getCaretOffset() {
+ return textarea.getCaretPosition();
+ }
+
+
+ /**
+ * True if some text is currently selected.
+ */
+ public boolean isSelectionActive() {
+ return textarea.isSelectionActive();
+ }
+
+
+ /**
+ * Get the beginning point of the current selection.
+ */
+ public int getSelectionStart() {
+ return textarea.getSelectionStart();
+ }
+
+
+ /**
+ * Get the end point of the current selection.
+ */
+ public int getSelectionStop() {
+ return textarea.getSelectionStop();
+ }
+
+
+ /**
+ * Get text for a specified line.
+ */
+ public String getLineText(int line) {
+ return textarea.getLineText(line);
+ }
+
+
+ /**
+ * Replace the text on a specified line.
+ */
+ public void setLineText(int line, String what) {
+ startCompoundEdit();
+ textarea.select(getLineStartOffset(line), getLineStopOffset(line));
+ textarea.setSelectedText(what);
+ stopCompoundEdit();
+ }
+
+
+ /**
+ * Get character offset for the start of a given line of text.
+ */
+ public int getLineStartOffset(int line) {
+ return textarea.getLineStartOffset(line);
+ }
+
+
+ /**
+ * Get character offset for end of a given line of text.
+ */
+ public int getLineStopOffset(int line) {
+ return textarea.getLineStopOffset(line);
+ }
+
+
+ /**
+ * Get the number of lines in the currently displayed buffer.
+ */
+ public int getLineCount() {
+ return textarea.getLineCount();
+ }
+
+
+ /**
+ * Use before a manipulating text to group editing operations together as a
+ * single undo. Use stopCompoundEdit() once finished.
+ */
+ public void startCompoundEdit() {
+ compoundEdit = new CompoundEdit();
+ }
+
+
+ /**
+ * Use with startCompoundEdit() to group edit operations in a single undo.
+ */
+ public void stopCompoundEdit() {
+ compoundEdit.end();
+ undo.addEdit(compoundEdit);
+ undoAction.updateUndoState();
+ redoAction.updateRedoState();
+ compoundEdit = null;
+ }
+
+
+ public int getScrollPosition() {
+ return textarea.getScrollPosition();
+ }
+
+
+ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+
+
+ /**
+ * Switch between tabs, this swaps out the Document object
+ * that's currently being manipulated.
+ */
+ protected void setCode(SketchCode code) {
+ SyntaxDocument document = (SyntaxDocument) code.getDocument();
+
+ if (document == null) { // this document not yet inited
+ document = new SyntaxDocument();
+ code.setDocument(document);
+
+ // turn on syntax highlighting
+ document.setTokenMarker(new PdeKeywords());
+
+ // insert the program text into the document object
+ try {
+ document.insertString(0, code.getProgram(), null);
+ } catch (BadLocationException bl) {
+ bl.printStackTrace();
+ }
+
+ // set up this guy's own undo manager
+// code.undo = new UndoManager();
+
+ // connect the undo listener to the editor
+ document.addUndoableEditListener(new UndoableEditListener() {
+ public void undoableEditHappened(UndoableEditEvent e) {
+ if (compoundEdit != null) {
+ compoundEdit.addEdit(e.getEdit());
+
+ } else if (undo != null) {
+ undo.addEdit(e.getEdit());
+ undoAction.updateUndoState();
+ redoAction.updateRedoState();
+ }
+ }
+ });
+ }
+
+ // update the document object that's in use
+ textarea.setDocument(document,
+ code.getSelectionStart(), code.getSelectionStop(),
+ code.getScrollPosition());
+
+ textarea.requestFocus(); // get the caret blinking
+
+ this.undo = code.getUndo();
+ undoAction.updateUndoState();
+ redoAction.updateRedoState();
+ }
+
+
+ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+
+
+ /**
+ * Implements Edit → Cut.
+ */
+ public void handleCut() {
+ textarea.cut();
+ sketch.setModified(true);
+ }
+
+
+ /**
+ * Implements Edit → Copy.
+ */
+ public void handleCopy() {
+ textarea.copy();
+ }
+
+
+ protected void handleDiscourseCopy() {
+ new DiscourseFormat(Editor.this).show();
+ }
+
+
+ /**
+ * Implements Edit → Paste.
+ */
+ public void handlePaste() {
+ textarea.paste();
+ sketch.setModified(true);
+ }
+
+
+ /**
+ * Implements Edit → Select All.
+ */
+ public void handleSelectAll() {
+ textarea.selectAll();
+ }
+
+
+ protected void handleCommentUncomment() {
+ startCompoundEdit();
+
+ int startLine = textarea.getSelectionStartLine();
+ int stopLine = textarea.getSelectionStopLine();
+
+ int lastLineStart = textarea.getLineStartOffset(stopLine);
+ int selectionStop = textarea.getSelectionStop();
+ // If the selection ends at the beginning of the last line,
+ // then don't (un)comment that line.
+ if (selectionStop == lastLineStart) {
+ // Though if there's no selection, don't do that
+ if (textarea.isSelectionActive()) {
+ stopLine--;
+ }
+ }
+
+ // If the text is empty, ignore the user.
+ // Also ensure that all lines are commented (not just the first)
+ // when determining whether to comment or uncomment.
+ int length = textarea.getDocumentLength();
+ boolean commented = true;
+ for (int i = startLine; commented && (i <= stopLine); i++) {
+ int pos = textarea.getLineStartOffset(i);
+ if (pos + 2 > length) {
+ commented = false;
+ } else {
+ // Check the first two characters to see if it's already a comment.
+ String begin = textarea.getText(pos, 2);
+ //System.out.println("begin is '" + begin + "'");
+ commented = begin.equals("//");
+ }
+ }
+
+ for (int line = startLine; line <= stopLine; line++) {
+ int location = textarea.getLineStartOffset(line);
+ if (commented) {
+ // remove a comment
+ textarea.select(location, location+2);
+ if (textarea.getSelectedText().equals("//")) {
+ textarea.setSelectedText("");
+ }
+ } else {
+ // add a comment
+ textarea.select(location, location);
+ textarea.setSelectedText("//");
+ }
+ }
+ // Subtract one from the end, otherwise selects past the current line.
+ // (Which causes subsequent calls to keep expanding the selection)
+ textarea.select(textarea.getLineStartOffset(startLine),
+ textarea.getLineStopOffset(stopLine) - 1);
+ stopCompoundEdit();
+ }
+
+
+ protected void handleIndentOutdent(boolean indent) {
+ int tabSize = Preferences.getInteger("editor.tabs.size");
+ String tabString = Editor.EMPTY.substring(0, tabSize);
+
+ startCompoundEdit();
+
+ int startLine = textarea.getSelectionStartLine();
+ int stopLine = textarea.getSelectionStopLine();
+
+ // If the selection ends at the beginning of the last line,
+ // then don't (un)comment that line.
+ int lastLineStart = textarea.getLineStartOffset(stopLine);
+ int selectionStop = textarea.getSelectionStop();
+ if (selectionStop == lastLineStart) {
+ // Though if there's no selection, don't do that
+ if (textarea.isSelectionActive()) {
+ stopLine--;
+ }
+ }
+
+ for (int line = startLine; line <= stopLine; line++) {
+ int location = textarea.getLineStartOffset(line);
+
+ if (indent) {
+ textarea.select(location, location);
+ textarea.setSelectedText(tabString);
+
+ } else { // outdent
+ textarea.select(location, location + tabSize);
+ // Don't eat code if it's not indented
+ if (textarea.getSelectedText().equals(tabString)) {
+ textarea.setSelectedText("");
+ }
+ }
+ }
+ // Subtract one from the end, otherwise selects past the current line.
+ // (Which causes subsequent calls to keep expanding the selection)
+ textarea.select(textarea.getLineStartOffset(startLine),
+ textarea.getLineStopOffset(stopLine) - 1);
+ stopCompoundEdit();
+ }
+
+
+ protected void handleFindReference() {
+ String text = textarea.getSelectedText().trim();
+
+ if (text.length() == 0) {
+ statusNotice("First select a word to find in the reference.");
+
+ } else {
+ String referenceFile = PdeKeywords.getReference(text);
+ //System.out.println("reference file is " + referenceFile);
+ if (referenceFile == null) {
+ statusNotice("No reference available for \"" + text + "\"");
+ } else {
+ Base.showReference(referenceFile + ".html");
+ }
+ }
+ }
+
+
+ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+
+
+ /**
+ * Implements Sketch → Run.
+ * @param present Set true to run in full screen (present mode).
+ */
+ public void handleRun(boolean present) {
+ internalCloseRunner();
+ running = true;
+ toolbar.activate(EditorToolbar.RUN);
+ statusEmpty();
+
+ // do this to advance/clear the terminal window / dos prompt / etc
+ for (int i = 0; i < 10; i++) System.out.println();
+
+ // clear the console on each run, unless the user doesn't want to
+ if (Preferences.getBoolean("console.auto_clear")) {
+ console.clear();
+ }
+
+ presenting = present;
+
+ try {
+ String appletClassName = sketch.compile();
+ if (appletClassName != null) {
+ runtime = new Runner(sketch, appletClassName, presenting, Editor.this);
+
+ // Cannot use invokeLater() here, otherwise it gets
+ // placed on the event thread and causes a hang--bad idea all around.
+ Thread t = new Thread(new Runnable() {
+ public void run() {
+ runtime.launch();
+ }
+ });
+ t.start();
+ //runtime.start(appletLocation);
+ }
+
+ } catch (Exception e) {
+ //System.err.println("exception reached editor");
+ //e.printStackTrace();
+ statusError(e);
+ }
+ }
+
+
+ /**
+ * Set the location of the sketch run window. Used by Runner to update the
+ * Editor about window drag events while the sketch is running.
+ */
+ public void setSketchLocation(Point p) {
+ sketchWindowLocation = p;
+ }
+
+
+ /**
+ * Get the last location of the sketch's run window. Used by Runner to make
+ * the window show up in the same location as when it was last closed.
+ */
+ public Point getSketchLocation() {
+ return sketchWindowLocation;
+ }
+
+
+ /**
+ * Implements Sketch → Stop, or pressing Stop on the toolbar.
+ */
+ public void handleStop() { // called by menu or buttons
+ toolbar.activate(EditorToolbar.STOP);
+
+ internalCloseRunner();
+
+ toolbar.deactivate(EditorToolbar.RUN);
+ toolbar.deactivate(EditorToolbar.STOP);
+
+ // focus the PDE again after quitting presentation mode [toxi 030903]
+ toFront();
+ }
+
+
+ /**
+ * Called by Runner to notify that the sketch has stopped running.
+ * Tools should not call this function, use handleStop() instead.
+ */
+ public void internalRunnerClosed() {
+ running = false;
+ toolbar.deactivate(EditorToolbar.RUN);
+ }
+
+
+ /**
+ * Handle internal shutdown of the runner.
+ */
+ public void internalCloseRunner() {
+ running = false;
+
+ try {
+ if (runtime != null) {
+ runtime.close(); // kills the window
+ runtime = null; // will this help?
+ }
+ } catch (Exception e) { }
+
+ sketch.cleanup();
+ }
+
+
+ /**
+ * Check if the sketch is modified and ask user to save changes.
+ * Immediately should be set true when quitting, or when the save should
+ * not happen asynchronously. Come to think of it, that's always now?
+ * @return false if canceling the close/quit operation
+ */
+ protected boolean checkModified(boolean immediately) {
+ if (!sketch.isModified()) return true;
+
+ String prompt = "Save changes to " + sketch.getName() + "? ";
+
+ if (!Base.isMacOS()) {
+ int result =
+ JOptionPane.showConfirmDialog(this, prompt, "Close",
+ JOptionPane.YES_NO_CANCEL_OPTION,
+ JOptionPane.QUESTION_MESSAGE);
+
+ if (result == JOptionPane.YES_OPTION) {
+ return handleSave(immediately);
+
+ } else if (result == JOptionPane.NO_OPTION) {
+ return true; // ok to continue
+
+ } else if (result == JOptionPane.CANCEL_OPTION) {
+ return false;
+ } else {
+ throw new IllegalStateException();
+ }
+
+ } else {
+ // This code is disabled unless Java 1.5 is being used on Mac OS X
+ // because of a Java bug that prevents the initial value of the
+ // dialog from being set properly (at least on my MacBook Pro).
+ // The bug causes the "Don't Save" option to be the highlighted,
+ // blinking, default. This sucks. But I'll tell you what doesn't
+ // suck--workarounds for the Mac and Apple's snobby attitude about it!
+ // I think it's nifty that they treat their developers like dirt.
+
+ // Pane formatting adapted from the quaqua guide
+ // http://www.randelshofer.ch/quaqua/guide/joptionpane.html
+ JOptionPane pane =
+ new JOptionPane(" " +
+ " " +
+ "Do you want to save changes to this sketch " +
+ " before closing?" +
+ "
If you don't save, your changes will be lost.",
+ JOptionPane.QUESTION_MESSAGE);
+
+ String[] options = new String[] {
+ "Save", "Cancel", "Don't Save"
+ };
+ pane.setOptions(options);
+
+ // highlight the safest option ala apple hig
+ pane.setInitialValue(options[0]);
+
+ // on macosx, setting the destructive property places this option
+ // away from the others at the lefthand side
+ pane.putClientProperty("Quaqua.OptionPane.destructiveOption",
+ new Integer(2));
+
+ JDialog dialog = pane.createDialog(this, null);
+ dialog.setVisible(true);
+
+ Object result = pane.getValue();
+ if (result == options[0]) { // save (and close/quit)
+ return handleSave(immediately);
+
+ } else if (result == options[2]) { // don't save (still close/quit)
+ return true;
+
+ } else { // cancel?
+ return false;
+ }
+ }
+ }
+
+
+ /**
+ * Open a sketch from a particular path, but don't check to save changes.
+ * Used by Sketch.saveAs() to re-open a sketch after the "Save As"
+ */
+ protected void handleOpenUnchecked(String path, int codeIndex,
+ int selStart, int selStop, int scrollPos) {
+ internalCloseRunner();
+ handleOpenInternal(path);
+ // Replacing a document that may be untitled. If this is an actual
+ // untitled document, then editor.untitled will be set by Base.
+ untitled = false;
+
+ sketch.setCurrentCode(codeIndex);
+ textarea.select(selStart, selStop);
+ textarea.setScrollPosition(scrollPos);
+ }
+
+
+ /**
+ * Second stage of open, occurs after having checked to see if the
+ * modifications (if any) to the previous sketch need to be saved.
+ */
+ protected boolean handleOpenInternal(String path) {
+ // check to make sure that this .pde file is
+ // in a folder of the same name
+ File file = new File(path);
+ File parentFile = new File(file.getParent());
+ String parentName = parentFile.getName();
+ String pdeName = parentName + ".pde";
+ File altFile = new File(file.getParent(), pdeName);
+
+ if (pdeName.equals(file.getName())) {
+ // no beef with this guy
+
+ } else if (altFile.exists()) {
+ // user selected a .java from the same sketch,
+ // but open the .pde instead
+ path = altFile.getAbsolutePath();
+ //System.out.println("found alt file in same folder");
+
+ } else if (!path.endsWith(".pde")) {
+ Base.showWarning("Bad file selected",
+ "Processing can only open its own sketches\n" +
+ "and other files ending in .pde", null);
+ return false;
+
+ } else {
+ String properParent =
+ file.getName().substring(0, file.getName().length() - 4);
+
+ Object[] options = { "OK", "Cancel" };
+ String prompt =
+ "The file \"" + file.getName() + "\" needs to be inside\n" +
+ "a sketch folder named \"" + properParent + "\".\n" +
+ "Create this folder, move the file, and continue?";
+
+ int result = JOptionPane.showOptionDialog(this,
+ prompt,
+ "Moving",
+ JOptionPane.YES_NO_OPTION,
+ JOptionPane.QUESTION_MESSAGE,
+ null,
+ options,
+ options[0]);
+
+ if (result == JOptionPane.YES_OPTION) {
+ // create properly named folder
+ File properFolder = new File(file.getParent(), properParent);
+ if (properFolder.exists()) {
+ Base.showWarning("Error",
+ "A folder named \"" + properParent + "\" " +
+ "already exists. Can't open sketch.", null);
+ return false;
+ }
+ if (!properFolder.mkdirs()) {
+ //throw new IOException("Couldn't create sketch folder");
+ Base.showWarning("Error",
+ "Could not create the sketch folder.", null);
+ return false;
+ }
+ // copy the sketch inside
+ File properPdeFile = new File(properFolder, file.getName());
+ File origPdeFile = new File(path);
+ try {
+ Base.copyFile(origPdeFile, properPdeFile);
+ } catch (IOException e) {
+ Base.showWarning("Error", "Could not copy to a proper location.", e);
+ return false;
+ }
+
+ // remove the original file, so user doesn't get confused
+ origPdeFile.delete();
+
+ // update with the new path
+ path = properPdeFile.getAbsolutePath();
+
+ } else if (result == JOptionPane.NO_OPTION) {
+ return false;
+ }
+ }
+
+ try {
+ sketch = new Sketch(this, path);
+ } catch (IOException e) {
+ Base.showWarning("Error", "Could not create the sketch.", e);
+ return false;
+ }
+ header.rebuild();
+ // Set the title of the window to "sketch_070752a - Processing 0126"
+ setTitle(sketch.getName() + " | Processing " + Base.VERSION_NAME);
+ // Disable untitled setting from previous document, if any
+ untitled = false;
+
+ // Store information on who's open and running
+ // (in case there's a crash or something that can't be recovered)
+ base.storeSketches();
+ Preferences.save();
+
+ // opening was successful
+ return true;
+
+// } catch (Exception e) {
+// e.printStackTrace();
+// statusError(e);
+// return false;
+// }
+ }
+
+
+ /**
+ * Actually handle the save command. If 'immediately' is set to false,
+ * this will happen in another thread so that the message area
+ * will update and the save button will stay highlighted while the
+ * save is happening. If 'immediately' is true, then it will happen
+ * immediately. This is used during a quit, because invokeLater()
+ * won't run properly while a quit is happening. This fixes
+ * Bug 276.
+ */
+ public boolean handleSave(boolean immediately) {
+ //stopRunner();
+ handleStop(); // 0136
+
+ if (untitled) {
+ return handleSaveAs();
+ // need to get the name, user might also cancel here
+
+ } else if (immediately) {
+ handleSave2();
+
+ } else {
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ handleSave2();
+ }
+ });
+ }
+ return true;
+ }
+
+
+ protected void handleSave2() {
+ toolbar.activate(EditorToolbar.SAVE);
+ statusNotice("Saving...");
+ try {
+ if (sketch.save()) {
+ statusNotice("Done Saving.");
+ } else {
+ statusEmpty();
+ }
+ // rebuild sketch menu in case a save-as was forced
+ // 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.
+ //sketchbook.rebuildMenus();
+ //sketchbook.rebuildMenusAsync();
+
+ } catch (Exception e) {
+ // show the error as a message in the window
+ statusError(e);
+
+ // zero out the current action,
+ // so that checkModified2 will just do nothing
+ //checkModifiedMode = 0;
+ // this is used when another operation calls a save
+ }
+ //toolbar.clear();
+ toolbar.deactivate(EditorToolbar.SAVE);
+ }
+
+
+ public boolean handleSaveAs() {
+ //stopRunner(); // formerly from 0135
+ handleStop();
+
+ toolbar.activate(EditorToolbar.SAVE);
+
+ //SwingUtilities.invokeLater(new Runnable() {
+ //public void run() {
+ statusNotice("Saving...");
+ try {
+ if (sketch.saveAs()) {
+ statusNotice("Done Saving.");
+ // 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.
+ //sketchbook.rebuildMenusAsync();
+ } else {
+ statusNotice("Save Canceled.");
+ return false;
+ }
+ } catch (Exception e) {
+ // show the error as a message in the window
+ statusError(e);
+
+ } finally {
+ // make sure the toolbar button deactivates
+ toolbar.deactivate(EditorToolbar.SAVE);
+ }
+
+ return true;
+ }
+
+
+ /**
+ * Called by Sketch → Export.
+ * Handles calling the export() function on sketch, and
+ * queues all the gui status stuff that comes along with it.
+ *
+ * Made synchronized to (hopefully) avoid problems of people
+ * hitting export twice, quickly, and horking things up.
+ */
+ synchronized public void handleExport() {
+ if (!handleExportCheckModified()) return;
+ toolbar.activate(EditorToolbar.EXPORT);
+
+ //SwingUtilities.invokeLater(new Runnable() {
+ Thread t = new Thread(new Runnable() {
+ public void run() {
+ try {
+ boolean success = sketch.exportApplet();
+ if (success) {
+ File appletFolder = new File(sketch.getFolder(), "applet");
+ Base.openFolder(appletFolder);
+ statusNotice("Done exporting.");
+ } else {
+ // error message will already be visible
+ }
+ } catch (Exception e) {
+ statusError(e);
+ }
+ //toolbar.clear();
+ toolbar.deactivate(EditorToolbar.EXPORT);
+ }});
+ t.start();
+ }
+
+
+ /**
+ * Handler for Sketch → Export Application
+ */
+ synchronized public void handleExportApplication() {
+ if (!handleExportCheckModified()) return;
+ toolbar.activate(EditorToolbar.EXPORT);
+
+ //SwingUtilities.invokeLater(new Runnable() {
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ statusNotice("Exporting application...");
+ try {
+ if (sketch.exportApplicationPrompt()) {
+ Base.openFolder(sketch.getFolder());
+ statusNotice("Done exporting.");
+ } else {
+ // error message will already be visible
+ // or there was no error, in which case it was canceled.
+ }
+ } catch (Exception e) {
+ statusNotice("Error during export.");
+ e.printStackTrace();
+ }
+ //toolbar.clear();
+ toolbar.deactivate(EditorToolbar.EXPORT);
+ }});
+ }
+
+
+ /**
+ * Checks to see if the sketch has been modified, and if so,
+ * asks the user to save the sketch or cancel the export.
+ * This prevents issues where an incomplete version of the sketch
+ * would be exported, and is a fix for
+ * Bug 157
+ */
+ protected boolean handleExportCheckModified() {
+ if (!sketch.isModified()) return true;
+
+ Object[] options = { "OK", "Cancel" };
+ int result = JOptionPane.showOptionDialog(this,
+ "Save changes before export?",
+ "Save",
+ JOptionPane.OK_CANCEL_OPTION,
+ JOptionPane.QUESTION_MESSAGE,
+ null,
+ options,
+ options[0]);
+
+ if (result == JOptionPane.OK_OPTION) {
+ handleSave(true);
+
+ } else {
+ // why it's not CANCEL_OPTION is beyond me (at least on the mac)
+ // but f-- it.. let's get this shite done..
+ //} else if (result == JOptionPane.CANCEL_OPTION) {
+ statusNotice("Export canceled, changes must first be saved.");
+ //toolbar.clear();
+ return false;
+ }
+ return true;
+ }
+
+
+ /**
+ * Handler for File → Page Setup.
+ */
+ public void handlePageSetup() {
+ //printerJob = null;
+ if (printerJob == null) {
+ printerJob = PrinterJob.getPrinterJob();
+ }
+ if (pageFormat == null) {
+ pageFormat = printerJob.defaultPage();
+ }
+ pageFormat = printerJob.pageDialog(pageFormat);
+ //System.out.println("page format is " + pageFormat);
+ }
+
+
+ /**
+ * Handler for File → Print.
+ */
+ public void handlePrint() {
+ statusNotice("Printing...");
+ //printerJob = null;
+ if (printerJob == null) {
+ printerJob = PrinterJob.getPrinterJob();
+ }
+ if (pageFormat != null) {
+ //System.out.println("setting page format " + pageFormat);
+ printerJob.setPrintable(textarea.getPainter(), pageFormat);
+ } else {
+ printerJob.setPrintable(textarea.getPainter());
+ }
+ // set the name of the job to the code name
+ printerJob.setJobName(sketch.getCurrentCode().getPrettyName());
+
+ if (printerJob.printDialog()) {
+ try {
+ printerJob.print();
+ statusNotice("Done printing.");
+
+ } catch (PrinterException pe) {
+ statusError("Error while printing.");
+ pe.printStackTrace();
+ }
+ } else {
+ statusNotice("Printing canceled.");
+ }
+ //printerJob = null; // clear this out?
+ }
+
+
+ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+
+
+ /**
+ * Show an error int the status bar.
+ */
+ public void statusError(String what) {
+ status.error(what);
+ //new Exception("deactivating RUN").printStackTrace();
+ toolbar.deactivate(EditorToolbar.RUN);
+ }
+
+
+ /**
+ * Show an exception in the editor status bar.
+ */
+ public void statusError(Exception e) {
+ e.printStackTrace();
+// if (e == null) {
+// System.err.println("Editor.statusError() was passed a null exception.");
+// return;
+// }
+
+ if (e instanceof RunnerException) {
+ RunnerException re = (RunnerException) e;
+ if (re.hasCodeIndex()) {
+ sketch.setCurrentCode(re.getCodeIndex());
+ }
+ if (re.hasCodeLine()) {
+ int line = re.getCodeLine();
+ // subtract one from the end so that the \n ain't included
+ if (line >= textarea.getLineCount()) {
+ // The error is at the end of this current chunk of code,
+ // so the last line needs to be selected.
+ line = textarea.getLineCount() - 1;
+ if (textarea.getLineText(line).length() == 0) {
+ // The last line may be zero length, meaning nothing to select.
+ // If so, back up one more line.
+ line--;
+ }
+ }
+ if (line < 0 || line >= textarea.getLineCount()) {
+ System.err.println("Bad error line: " + line);
+ } else {
+ textarea.select(textarea.getLineStartOffset(line),
+ textarea.getLineStopOffset(line) - 1);
+ }
+ }
+ }
+
+ // Since this will catch all Exception types, spend some time figuring
+ // out which kind and try to give a better error message to the user.
+ String mess = e.getMessage();
+ if (mess != null) {
+ String javaLang = "java.lang.";
+ if (mess.indexOf(javaLang) == 0) {
+ mess = mess.substring(javaLang.length());
+ }
+ String rxString = "RuntimeException: ";
+ if (mess.indexOf(rxString) == 0) {
+ mess = mess.substring(rxString.length());
+ }
+ statusError(mess);
+ }
+ e.printStackTrace();
+ }
+
+
+ /**
+ * Show a notice message in the editor status bar.
+ */
+ public void statusNotice(String msg) {
+ status.notice(msg);
+ }
+
+
+ /**
+ * Clear the status area.
+ */
+ public void statusEmpty() {
+ statusNotice(EMPTY);
+ }
+
+
+ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+
+
+ /**
+ * Returns the edit popup menu.
+ */
+ class TextAreaPopup extends JPopupMenu {
+ //String currentDir = System.getProperty("user.dir");
+ String referenceFile = null;
+
+ JMenuItem cutItem;
+ JMenuItem copyItem;
+ JMenuItem discourseItem;
+ JMenuItem referenceItem;
+
+
+ public TextAreaPopup() {
+ JMenuItem item;
+
+ cutItem = new JMenuItem("Cut");
+ cutItem.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ handleCut();
+ }
+ });
+ this.add(cutItem);
+
+ copyItem = new JMenuItem("Copy");
+ copyItem.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ handleCopy();
+ }
+ });
+ this.add(copyItem);
+
+ discourseItem = new JMenuItem("Copy for Discourse");
+ discourseItem.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ handleDiscourseCopy();
+ }
+ });
+ this.add(discourseItem);
+
+ item = new JMenuItem("Paste");
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ handlePaste();
+ }
+ });
+ this.add(item);
+
+ item = new JMenuItem("Select All");
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ handleSelectAll();
+ }
+ });
+ this.add(item);
+
+ this.addSeparator();
+
+ item = new JMenuItem("Comment/Uncomment");
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ handleCommentUncomment();
+ }
+ });
+ this.add(item);
+
+ item = new JMenuItem("Increase Indent");
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ handleIndentOutdent(true);
+ }
+ });
+ this.add(item);
+
+ item = new JMenuItem("Decrease Indent");
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ handleIndentOutdent(false);
+ }
+ });
+ this.add(item);
+
+ this.addSeparator();
+
+ referenceItem = new JMenuItem("Find in Reference");
+ referenceItem.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ handleFindReference();
+ }
+ });
+ this.add(referenceItem);
+ }
+
+ // if no text is selected, disable copy and cut menu items
+ public void show(Component component, int x, int y) {
+ if (textarea.isSelectionActive()) {
+ cutItem.setEnabled(true);
+ copyItem.setEnabled(true);
+ discourseItem.setEnabled(true);
+
+ String sel = textarea.getSelectedText().trim();
+ referenceFile = PdeKeywords.getReference(sel);
+ referenceItem.setEnabled(referenceFile != null);
+
+ } else {
+ cutItem.setEnabled(false);
+ copyItem.setEnabled(false);
+ discourseItem.setEnabled(false);
+ referenceItem.setEnabled(false);
+ }
+ super.show(component, x, y);
+ }
+ }
+}
+
diff --git a/app/src/processing/app/EditorConsole.java b/app/src/processing/app/EditorConsole.java
new file mode 100644
index 000000000..e8dc578f1
--- /dev/null
+++ b/app/src/processing/app/EditorConsole.java
@@ -0,0 +1,460 @@
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+/*
+ Part of the Processing project - http://processing.org
+
+ Copyright (c) 2004-06 Ben Fry and Casey Reas
+ Copyright (c) 2001-04 Massachusetts Institute of Technology
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+package processing.app;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import javax.swing.*;
+import javax.swing.text.*;
+import java.util.*;
+
+
+/**
+ * Message console that sits below the editing area.
+ *
+ * Debugging this class is tricky... If it's throwing exceptions,
+ * don't take over System.err, and debug while watching just System.out
+ * or just write println() or whatever directly to systemOut or systemErr.
+ */
+public class EditorConsole extends JScrollPane {
+ Editor editor;
+
+ JTextPane consoleTextPane;
+ BufferedStyledDocument consoleDoc;
+
+ MutableAttributeSet stdStyle;
+ MutableAttributeSet errStyle;
+
+ boolean cerror;
+
+ int maxLineCount;
+
+ static File errFile;
+ static File outFile;
+ static File tempFolder;
+
+ // Single static instance shared because there's only one real System.out.
+ // Within the input handlers, the currentConsole variable will be used to
+ // echo things to the correct location.
+
+ static public PrintStream systemOut;
+ static public PrintStream systemErr;
+
+ static PrintStream consoleOut;
+ static PrintStream consoleErr;
+
+ static OutputStream stdoutFile;
+ static OutputStream stderrFile;
+
+ static EditorConsole currentConsole;
+
+
+ public EditorConsole(Editor editor) {
+ this.editor = editor;
+
+ maxLineCount = Preferences.getInteger("console.length");
+
+ consoleDoc = new BufferedStyledDocument(10000, maxLineCount);
+ consoleTextPane = new JTextPane(consoleDoc);
+ consoleTextPane.setEditable(false);
+
+ // necessary?
+ MutableAttributeSet standard = new SimpleAttributeSet();
+ StyleConstants.setAlignment(standard, StyleConstants.ALIGN_LEFT);
+ consoleDoc.setParagraphAttributes(0, 0, standard, true);
+
+ // build styles for different types of console output
+ Color bgColor = Theme.getColor("console.color");
+ Color fgColorOut = Theme.getColor("console.output.color");
+ Color fgColorErr = Theme.getColor("console.error.color");
+ Font font = Theme.getFont("console.font");
+
+ stdStyle = new SimpleAttributeSet();
+ StyleConstants.setForeground(stdStyle, fgColorOut);
+ StyleConstants.setBackground(stdStyle, bgColor);
+ StyleConstants.setFontSize(stdStyle, font.getSize());
+ StyleConstants.setFontFamily(stdStyle, font.getFamily());
+ StyleConstants.setBold(stdStyle, font.isBold());
+ StyleConstants.setItalic(stdStyle, font.isItalic());
+
+ errStyle = new SimpleAttributeSet();
+ StyleConstants.setForeground(errStyle, fgColorErr);
+ StyleConstants.setBackground(errStyle, bgColor);
+ StyleConstants.setFontSize(errStyle, font.getSize());
+ StyleConstants.setFontFamily(errStyle, font.getFamily());
+ StyleConstants.setBold(errStyle, font.isBold());
+ StyleConstants.setItalic(errStyle, font.isItalic());
+
+ consoleTextPane.setBackground(bgColor);
+
+ // add the jtextpane to this scrollpane
+ this.setViewportView(consoleTextPane);
+
+ // calculate height of a line of text in pixels
+ // and size window accordingly
+ FontMetrics metrics = this.getFontMetrics(font);
+ int height = metrics.getAscent() + metrics.getDescent();
+ int lines = Preferences.getInteger("console.lines"); //, 4);
+ int sizeFudge = 6; //10; // unclear why this is necessary, but it is
+ setPreferredSize(new Dimension(1024, (height * lines) + sizeFudge));
+ setMinimumSize(new Dimension(1024, (height * 4) + sizeFudge));
+
+ if (systemOut == null) {
+ systemOut = System.out;
+ systemErr = System.err;
+
+ // Create a temporary folder which will have a randomized name. Has to
+ // be randomized otherwise another instance of Processing (or one of its
+ // sister IDEs) might collide with the file causing permissions problems.
+ // The files and folders are not deleted on exit because they may be
+ // needed for debugging or bug reporting.
+ tempFolder = Base.createTempFolder("console");
+ try {
+ String outFileName = Preferences.get("console.output.file");
+ if (outFileName != null) {
+ outFile = new File(tempFolder, outFileName);
+ stdoutFile = new FileOutputStream(outFile);
+ }
+
+ String errFileName = Preferences.get("console.error.file");
+ if (errFileName != null) {
+ errFile = new File(tempFolder, errFileName);
+ stderrFile = new FileOutputStream(errFile);
+ }
+ } catch (IOException e) {
+ Base.showWarning("Console Error",
+ "A problem occurred while trying to open the\n" +
+ "files used to store the console output.", e);
+ }
+ consoleOut = new PrintStream(new EditorConsoleStream(false));
+ consoleErr = new PrintStream(new EditorConsoleStream(true));
+
+ if (Preferences.getBoolean("console")) {
+ try {
+ System.setOut(consoleOut);
+ System.setErr(consoleErr);
+ } catch (Exception e) {
+ e.printStackTrace(systemOut);
+ }
+ }
+ }
+
+ // to fix ugliness.. normally macosx java 1.3 puts an
+ // ugly white border around this object, so turn it off.
+ if (Base.isMacOS()) {
+ setBorder(null);
+ }
+
+ // periodically post buffered messages to the console
+ // should the interval come from the preferences file?
+ new javax.swing.Timer(250, new ActionListener() {
+ public void actionPerformed(ActionEvent evt) {
+ // only if new text has been added
+ if (consoleDoc.hasAppendage) {
+ // insert the text that's been added in the meantime
+ consoleDoc.insertAll();
+ // always move to the end of the text as it's added
+ consoleTextPane.setCaretPosition(consoleDoc.getLength());
+ }
+ }
+ }).start();
+ }
+
+
+ static public void setEditor(Editor editor) {
+ currentConsole = editor.console;
+ }
+
+
+ /**
+ * Close the streams so that the temporary files can be deleted.
+ *
+ * File.deleteOnExit() cannot be used because the stdout and stderr
+ * files are inside a folder, and have to be deleted before the
+ * folder itself is deleted, which can't be guaranteed when using
+ * the deleteOnExit() method.
+ */
+ public void handleQuit() {
+ // replace original streams to remove references to console's streams
+ System.setOut(systemOut);
+ System.setErr(systemErr);
+
+ // close the PrintStream
+ consoleOut.close();
+ consoleErr.close();
+
+ // also have to close the original FileOutputStream
+ // otherwise it won't be shut down completely
+ try {
+ stdoutFile.close();
+ stderrFile.close();
+ } catch (IOException e) {
+ e.printStackTrace(systemOut);
+ }
+
+ outFile.delete();
+ errFile.delete();
+ tempFolder.delete();
+ }
+
+
+ public void write(byte b[], int offset, int length, boolean err) {
+ if (err != cerror) {
+ // advance the line because switching between err/out streams
+ // potentially, could check whether we're already on a new line
+ message("", cerror, true);
+ }
+
+ // we could do some cross platform CR/LF mangling here before outputting
+
+ // add text to output document
+ message(new String(b, offset, length), err, false);
+ // set last error state
+ cerror = err;
+ }
+
+
+ // added sync for 0091.. not sure if it helps or hinders
+ synchronized public void message(String what, boolean err, boolean advance) {
+ if (err) {
+ systemErr.print(what);
+ //systemErr.print("CE" + what);
+ } else {
+ systemOut.print(what);
+ //systemOut.print("CO" + what);
+ }
+
+ if (advance) {
+ appendText("\n", err);
+ if (err) {
+ systemErr.println();
+ } else {
+ systemOut.println();
+ }
+ }
+
+ // to console display
+ appendText(what, err);
+ // moved down here since something is punting
+ }
+
+
+ /**
+ * Append a piece of text to the console.
+ *
+ * Swing components are NOT thread-safe, and since the MessageSiphon
+ * instantiates new threads, and in those callbacks, they often print
+ * output to stdout and stderr, which are wrapped by EditorConsoleStream
+ * and eventually leads to EditorConsole.appendText(), which directly
+ * updates the Swing text components, causing deadlock.
+ *
+ * Updates are buffered to the console and displayed at regular
+ * intervals on Swing's event-dispatching thread. (patch by David Mellis)
+ */
+ synchronized private void appendText(String txt, boolean e) {
+ consoleDoc.appendString(txt, e ? errStyle : stdStyle);
+ }
+
+
+ public void clear() {
+ try {
+ consoleDoc.remove(0, consoleDoc.getLength());
+ } catch (BadLocationException e) {
+ // ignore the error otherwise this will cause an infinite loop
+ // maybe not a good idea in the long run?
+ }
+ }
+
+
+ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+
+
+ class EditorConsoleStream extends OutputStream {
+ //static EditorConsole current;
+ boolean err; // whether stderr or stdout
+ byte single[] = new byte[1];
+
+ public EditorConsoleStream(boolean err) {
+ this.err = err;
+ }
+
+ public void close() { }
+
+ public void flush() { }
+
+ public void write(byte b[]) { // appears never to be used
+// if (currentConsole.isDisplayable()) {
+ currentConsole.write(b, 0, b.length, err);
+// } else {
+// systemOut.println("not displayable");
+// if (err) {
+// systemErr.write(b, 0, b.length);
+// } else {
+// systemOut.write(b, 0, b.length);
+// }
+// }
+
+ OutputStream echo = err ? stderrFile : stdoutFile;
+ if (echo != null) {
+ try {
+ echo.write(b);
+ echo.flush();
+ } catch (IOException e) {
+ e.printStackTrace();
+ echo = null;
+ }
+ }
+ }
+
+ public void write(byte b[], int offset, int length) {
+ currentConsole.write(b, offset, length, err);
+// if (currentConsole.isDisplayable()) {
+// systemOut.println("is displayable");
+// currentConsole.write(b, offset, length, err);
+// } else {
+// systemOut.println("not displayable");
+// if (err) {
+// systemErr.write(b, offset, length);
+// } else {
+// systemOut.write(b, offset, length);
+// }
+// }
+
+ OutputStream echo = err ? stderrFile : stdoutFile;
+ if (echo != null) {
+ try {
+ echo.write(b, offset, length);
+ echo.flush();
+ } catch (IOException e) {
+ e.printStackTrace();
+ echo = null;
+ }
+ }
+ }
+
+ public void write(int b) {
+ single[0] = (byte)b;
+ currentConsole.write(single, 0, 1, err);
+
+ OutputStream echo = err ? stderrFile : stdoutFile;
+ if (echo != null) {
+ try {
+ echo.write(b);
+ echo.flush();
+ } catch (IOException e) {
+ e.printStackTrace();
+ echo = null;
+ }
+ }
+ }
+ }
+}
+
+
+// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+
+
+/**
+ * Buffer updates to the console and output them in batches. For info, see:
+ * http://java.sun.com/products/jfc/tsc/articles/text/element_buffer and
+ * http://javatechniques.com/public/java/docs/gui/jtextpane-speed-part2.html
+ * appendString() is called from multiple threads, and insertAll from the
+ * swing event thread, so they need to be synchronized
+ */
+class BufferedStyledDocument extends DefaultStyledDocument {
+ ArrayList elements = new ArrayList();
+ int maxLineLength, maxLineCount;
+ int currentLineLength = 0;
+ boolean needLineBreak = false;
+ boolean hasAppendage = false;
+
+ public BufferedStyledDocument(int maxLineLength, int maxLineCount) {
+ this.maxLineLength = maxLineLength;
+ this.maxLineCount = maxLineCount;
+ }
+
+ /** buffer a string for insertion at the end of the DefaultStyledDocument */
+ public synchronized void appendString(String str, AttributeSet a) {
+ // do this so that it's only updated when needed (otherwise console
+ // updates every 250 ms when an app isn't even running.. see bug 180)
+ hasAppendage = true;
+
+ // process each line of the string
+ while (str.length() > 0) {
+ // newlines within an element have (almost) no effect, so we need to
+ // replace them with proper paragraph breaks (start and end tags)
+ if (needLineBreak || currentLineLength > maxLineLength) {
+ elements.add(new ElementSpec(a, ElementSpec.EndTagType));
+ elements.add(new ElementSpec(a, ElementSpec.StartTagType));
+ currentLineLength = 0;
+ }
+
+ if (str.indexOf('\n') == -1) {
+ elements.add(new ElementSpec(a, ElementSpec.ContentType,
+ str.toCharArray(), 0, str.length()));
+ currentLineLength += str.length();
+ needLineBreak = false;
+ str = str.substring(str.length()); // eat the string
+ } else {
+ elements.add(new ElementSpec(a, ElementSpec.ContentType,
+ str.toCharArray(), 0, str.indexOf('\n') + 1));
+ needLineBreak = true;
+ str = str.substring(str.indexOf('\n') + 1); // eat the line
+ }
+ }
+ }
+
+ /** insert the buffered strings */
+ public synchronized void insertAll() {
+ ElementSpec[] elementArray = new ElementSpec[elements.size()];
+ elements.toArray(elementArray);
+
+ try {
+ // check how many lines have been used so far
+ // if too many, shave off a few lines from the beginning
+ Element element = super.getDefaultRootElement();
+ int lineCount = element.getElementCount();
+ int overage = lineCount - maxLineCount;
+ if (overage > 0) {
+ // if 1200 lines, and 1000 lines is max,
+ // find the position of the end of the 200th line
+ //systemOut.println("overage is " + overage);
+ Element lineElement = element.getElement(overage);
+ if (lineElement == null) return; // do nuthin
+
+ int endOffset = lineElement.getEndOffset();
+ // remove to the end of the 200th line
+ super.remove(0, endOffset);
+ }
+ super.insert(super.getLength(), elementArray);
+
+ } catch (BadLocationException e) {
+ // ignore the error otherwise this will cause an infinite loop
+ // maybe not a good idea in the long run?
+ }
+ elements.clear();
+ hasAppendage = false;
+ }
+}
diff --git a/app/src/processing/app/EditorHeader.java b/app/src/processing/app/EditorHeader.java
new file mode 100644
index 000000000..1dc7d4422
--- /dev/null
+++ b/app/src/processing/app/EditorHeader.java
@@ -0,0 +1,394 @@
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+/*
+ Part of the Processing project - http://processing.org
+
+ Copyright (c) 2004-08 Ben Fry and Casey Reas
+ Copyright (c) 2001-04 Massachusetts Institute of Technology
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+package processing.app;
+
+import java.awt.*;
+import java.awt.event.*;
+
+import javax.swing.*;
+
+
+/**
+ * Sketch tabs at the top of the editor window.
+ */
+public class EditorHeader extends JComponent {
+ static Color backgroundColor;
+ static Color textColor[] = new Color[2];
+
+ Editor editor;
+
+ int tabLeft[];
+ int tabRight[];
+
+ Font font;
+ FontMetrics metrics;
+ int fontAscent;
+
+ JMenu menu;
+ JPopupMenu popup;
+
+ int menuLeft;
+ int menuRight;
+
+ //
+
+ static final String STATUS[] = { "unsel", "sel" };
+ static final int UNSELECTED = 0;
+ static final int SELECTED = 1;
+
+ static final String WHERE[] = { "left", "mid", "right", "menu" };
+ static final int LEFT = 0;
+ static final int MIDDLE = 1;
+ static final int RIGHT = 2;
+ static final int MENU = 3;
+
+ static final int PIECE_WIDTH = 4;
+
+ static Image[][] pieces;
+
+ //
+
+ Image offscreen;
+ int sizeW, sizeH;
+ int imageW, imageH;
+
+
+ public EditorHeader(Editor eddie) {
+ this.editor = eddie; // weird name for listener
+
+ if (pieces == null) {
+ pieces = new Image[STATUS.length][WHERE.length];
+ for (int i = 0; i < STATUS.length; i++) {
+ for (int j = 0; j < WHERE.length; j++) {
+ String path = "tab-" + STATUS[i] + "-" + WHERE[j] + ".gif";
+ pieces[i][j] = Base.getThemeImage(path, this);
+ }
+ }
+ }
+
+ if (backgroundColor == null) {
+ backgroundColor =
+ Theme.getColor("header.bgcolor");
+ textColor[SELECTED] =
+ Theme.getColor("header.text.selected.color");
+ textColor[UNSELECTED] =
+ Theme.getColor("header.text.unselected.color");
+ }
+
+ addMouseListener(new MouseAdapter() {
+ public void mousePressed(MouseEvent e) {
+ int x = e.getX();
+ int y = e.getY();
+
+ if ((x > menuLeft) && (x < menuRight)) {
+ popup.show(EditorHeader.this, x, y);
+
+ } else {
+ Sketch sketch = editor.getSketch();
+ for (int i = 0; i < sketch.getCodeCount(); i++) {
+ if ((x > tabLeft[i]) && (x < tabRight[i])) {
+ sketch.setCurrentCode(i);
+ repaint();
+ }
+ }
+ }
+ }
+ });
+ }
+
+
+ public void paintComponent(Graphics screen) {
+ if (screen == null) return;
+
+ Sketch sketch = editor.getSketch();
+ if (sketch == null) return; // ??
+
+ Dimension size = getSize();
+ if ((size.width != sizeW) || (size.height != sizeH)) {
+ // component has been resized
+
+ if ((size.width > imageW) || (size.height > imageH)) {
+ // nix the image and recreate, it's too small
+ offscreen = null;
+
+ } else {
+ // who cares, just resize
+ sizeW = size.width;
+ sizeH = size.height;
+ }
+ }
+
+ if (offscreen == null) {
+ sizeW = size.width;
+ sizeH = size.height;
+ imageW = sizeW;
+ imageH = sizeH;
+ offscreen = createImage(imageW, imageH);
+ }
+
+ Graphics g = offscreen.getGraphics();
+ if (font == null) {
+ font = Theme.getFont("header.text.font");
+ }
+ g.setFont(font); // need to set this each time through
+ metrics = g.getFontMetrics();
+ fontAscent = metrics.getAscent();
+ //}
+
+ //Graphics2D g2 = (Graphics2D) g;
+ //g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
+ // RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+
+ // set the background for the offscreen
+ g.setColor(backgroundColor);
+ g.fillRect(0, 0, imageW, imageH);
+
+ int codeCount = sketch.getCodeCount();
+ if ((tabLeft == null) || (tabLeft.length < codeCount)) {
+ tabLeft = new int[codeCount];
+ tabRight = new int[codeCount];
+ }
+
+ int x = 6; // offset from left edge of the component
+ for (int i = 0; i < sketch.getCodeCount(); i++) {
+ SketchCode code = sketch.getCode(i);
+
+ String codeName = sketch.hideExtension(code.getExtension()) ?
+ code.getPrettyName() : code.getFileName();
+
+ // if modified, add the li'l glyph next to the name
+ String text = " " + codeName + (code.isModified() ? " \u00A7" : " ");
+
+ Graphics2D g2 = (Graphics2D) g;
+ int textWidth = (int)
+ font.getStringBounds(text, g2.getFontRenderContext()).getWidth();
+
+ int pieceCount = 2 + (textWidth / PIECE_WIDTH);
+ int pieceWidth = pieceCount * PIECE_WIDTH;
+
+ int state = (code == sketch.getCurrentCode()) ? SELECTED : UNSELECTED;
+ g.drawImage(pieces[state][LEFT], x, 0, null);
+ x += PIECE_WIDTH;
+
+ int contentLeft = x;
+ tabLeft[i] = x;
+ for (int j = 0; j < pieceCount; j++) {
+ g.drawImage(pieces[state][MIDDLE], x, 0, null);
+ x += PIECE_WIDTH;
+ }
+ tabRight[i] = x;
+ int textLeft = contentLeft + (pieceWidth - textWidth) / 2;
+
+ g.setColor(textColor[state]);
+ int baseline = (sizeH + fontAscent) / 2;
+ //g.drawString(sketch.code[i].name, textLeft, baseline);
+ g.drawString(text, textLeft, baseline);
+
+ g.drawImage(pieces[state][RIGHT], x, 0, null);
+ x += PIECE_WIDTH - 1; // overlap by 1 pixel
+ }
+
+ menuLeft = sizeW - (16 + pieces[0][MENU].getWidth(this));
+ menuRight = sizeW - 16;
+ // draw the dropdown menu target
+ g.drawImage(pieces[popup.isVisible() ? SELECTED : UNSELECTED][MENU],
+ menuLeft, 0, null);
+
+ screen.drawImage(offscreen, 0, 0, null);
+ }
+
+
+ /**
+ * Called when a new sketch is opened.
+ */
+ public void rebuild() {
+ //System.out.println("rebuilding editor header");
+ rebuildMenu();
+ repaint();
+ Toolkit.getDefaultToolkit().sync();
+ }
+
+
+ public void rebuildMenu() {
+ //System.out.println("rebuilding");
+ if (menu != null) {
+ menu.removeAll();
+
+ } else {
+ menu = new JMenu();
+ popup = menu.getPopupMenu();
+ add(popup);
+ popup.setLightWeightPopupEnabled(true);
+
+ /*
+ popup.addPopupMenuListener(new PopupMenuListener() {
+ public void popupMenuCanceled(PopupMenuEvent e) {
+ // on redraw, the isVisible() will get checked.
+ // actually, a repaint may be fired anyway, so this
+ // may be redundant.
+ repaint();
+ }
+
+ public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { }
+ public void popupMenuWillBecomeVisible(PopupMenuEvent e) { }
+ });
+ */
+ }
+ JMenuItem item;
+
+ // maybe this shouldn't have a command key anyways..
+ // since we're not trying to make this a full ide..
+ //item = Editor.newJMenuItem("New", 'T');
+
+ /*
+ item = Editor.newJMenuItem("Previous", KeyEvent.VK_PAGE_UP);
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ System.out.println("prev");
+ }
+ });
+ if (editor.sketch != null) {
+ item.setEnabled(editor.sketch.codeCount > 1);
+ }
+ menu.add(item);
+
+ item = Editor.newJMenuItem("Next", KeyEvent.VK_PAGE_DOWN);
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ System.out.println("ext");
+ }
+ });
+ if (editor.sketch != null) {
+ item.setEnabled(editor.sketch.codeCount > 1);
+ }
+ menu.add(item);
+
+ menu.addSeparator();
+ */
+
+ //item = new JMenuItem("New Tab");
+ item = Editor.newJMenuItemShift("New Tab", 'N');
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ editor.getSketch().handleNewCode();
+ }
+ });
+ menu.add(item);
+
+ item = new JMenuItem("Rename");
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ editor.getSketch().handleRenameCode();
+ /*
+ // this is already being called by nameCode(), the second stage of rename
+ if (editor.sketch.current == editor.sketch.code[0]) {
+ editor.sketchbook.rebuildMenus();
+ }
+ */
+ }
+ });
+ menu.add(item);
+
+ item = new JMenuItem("Delete");
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ editor.getSketch().handleDeleteCode();
+ }
+ });
+ menu.add(item);
+
+ menu.addSeparator();
+
+ // KeyEvent.VK_LEFT and VK_RIGHT will make Windows beep
+
+ item = new JMenuItem("Previous Tab");
+ KeyStroke ctrlAltLeft =
+ KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, Editor.SHORTCUT_ALT_KEY_MASK);
+ item.setAccelerator(ctrlAltLeft);
+ // this didn't want to work consistently
+ /*
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ editor.sketch.prevCode();
+ }
+ });
+ */
+ menu.add(item);
+
+ item = new JMenuItem("Next Tab");
+ KeyStroke ctrlAltRight =
+ KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, Editor.SHORTCUT_ALT_KEY_MASK);
+ item.setAccelerator(ctrlAltRight);
+ /*
+ item.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ editor.sketch.nextCode();
+ }
+ });
+ */
+ menu.add(item);
+
+ Sketch sketch = editor.getSketch();
+ if (sketch != null) {
+ menu.addSeparator();
+
+ ActionListener jumpListener = new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ editor.getSketch().setCurrentCode(e.getActionCommand());
+ }
+ };
+ for (SketchCode code : sketch.getCode()) {
+ item = new JMenuItem(code.getPrettyName());
+ item.addActionListener(jumpListener);
+ menu.add(item);
+ }
+ }
+ }
+
+
+ public void deselectMenu() {
+ repaint();
+ }
+
+
+ public Dimension getPreferredSize() {
+ return getMinimumSize();
+ }
+
+
+ public Dimension getMinimumSize() {
+ if (Base.isMacOS()) {
+ return new Dimension(300, Preferences.GRID_SIZE);
+ }
+ return new Dimension(300, Preferences.GRID_SIZE - 1);
+ }
+
+
+ public Dimension getMaximumSize() {
+ if (Base.isMacOS()) {
+ return new Dimension(3000, Preferences.GRID_SIZE);
+ }
+ return new Dimension(3000, Preferences.GRID_SIZE - 1);
+ }
+}
diff --git a/app/src/processing/app/EditorLineStatus.java b/app/src/processing/app/EditorLineStatus.java
new file mode 100644
index 000000000..f28175ff0
--- /dev/null
+++ b/app/src/processing/app/EditorLineStatus.java
@@ -0,0 +1,116 @@
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+/*
+ Part of the Processing project - http://processing.org
+
+ Copyright (c) 2005-07 Ben Fry and Casey Reas
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+package processing.app;
+
+import processing.app.syntax.*;
+
+import java.awt.*;
+import javax.swing.*;
+
+
+/**
+ * Li'l status bar fella that shows the line number.
+ */
+public class EditorLineStatus extends JComponent {
+ JEditTextArea textarea;
+ int start = -1, stop;
+
+ Image resize;
+
+ Color foreground;
+ Color background;
+ Font font;
+ int high;
+
+ String text = "";
+
+
+ public EditorLineStatus(JEditTextArea textarea) {
+ this.textarea = textarea;
+ textarea.editorLineStatus = this;
+
+ background = Theme.getColor("linestatus.bgcolor");
+ font = Theme.getFont("linestatus.font");
+ foreground = Theme.getColor("linestatus.color");
+ high = Theme.getInteger("linestatus.height");
+
+ if (Base.isMacOS()) {
+ resize = Base.getThemeImage("resize.gif", this);
+ }
+ //linestatus.bgcolor = #000000
+ //linestatus.font = SansSerif,plain,10
+ //linestatus.color = #FFFFFF
+ }
+
+
+ public void set(int newStart, int newStop) {
+ if ((newStart == start) && (newStop == stop)) return;
+
+ start = newStart;
+ stop = newStop;
+
+ /*
+ if (start == stop) {
+ text = "Line " + (start + 1);
+ } else {
+ text = "Lines " + (start + 1) + " to " + (stop + 1);
+ }
+ */
+ if (start == stop) {
+ text = String.valueOf(start+1);
+ } else {
+ text = (start+1) + " - " + (stop+1);
+ }
+
+ repaint();
+ }
+
+
+ public void paintComponent(Graphics g) {
+ g.setColor(background);
+ Dimension size = getSize();
+ g.fillRect(0, 0, size.width, size.height);
+
+ g.setFont(font);
+ g.setColor(foreground);
+ int baseline = (high + g.getFontMetrics().getAscent()) / 2;
+ g.drawString(text, 6, baseline);
+
+ if (Base.isMacOS()) {
+ g.drawImage(resize, size.width - 20, 0, this);
+ }
+ }
+
+
+ public Dimension getPreferredSize() {
+ return new Dimension(300, high);
+ }
+
+ public Dimension getMinimumSize() {
+ return getPreferredSize();
+ }
+
+ public Dimension getMaximumSize() {
+ return new Dimension(3000, high);
+ }
+}
diff --git a/app/src/processing/app/EditorListener.java b/app/src/processing/app/EditorListener.java
new file mode 100644
index 000000000..ffd05b022
--- /dev/null
+++ b/app/src/processing/app/EditorListener.java
@@ -0,0 +1,612 @@
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+/*
+ Part of the Processing project - http://processing.org
+
+ Copyright (c) 2004-08 Ben Fry and Casey Reas
+ Copyright (c) 2001-04 Massachusetts Institute of Technology
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+package processing.app;
+
+import processing.app.syntax.*;
+
+import java.awt.*;
+import java.awt.event.*;
+
+
+/**
+ * Filters key events for tab expansion/indent/etc.
+ *
+ * For version 0099, some changes have been made to make the indents
+ * smarter. There are still issues though:
+ * + indent happens when it picks up a curly brace on the previous line,
+ * but not if there's a blank line between them.
+ * + It also doesn't handle single indent situations where a brace
+ * isn't used (i.e. an if statement or for loop that's a single line).
+ * It shouldn't actually be using braces.
+ * Solving these issues, however, would probably best be done by a
+ * smarter parser/formatter, rather than continuing to hack this class.
+ */
+public class EditorListener {
+ private Editor editor;
+ private JEditTextArea textarea;
+
+ private boolean externalEditor;
+ private boolean tabsExpand;
+ private boolean tabsIndent;
+ private int tabSize;
+ private String tabString;
+ private boolean autoIndent;
+
+// private int selectionStart, selectionEnd;
+// private int position;
+
+ /** ctrl-alt on windows and linux, cmd-alt on mac os x */
+ static final int CTRL_ALT = ActionEvent.ALT_MASK |
+ Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
+
+
+ public EditorListener(Editor editor, JEditTextArea textarea) {
+ this.editor = editor;
+ this.textarea = textarea;
+
+ // let him know that i'm leechin'
+ textarea.editorListener = this;
+
+ applyPreferences();
+ }
+
+
+ public void applyPreferences() {
+ tabsExpand = Preferences.getBoolean("editor.tabs.expand");
+ //tabsIndent = Preferences.getBoolean("editor.tabs.indent");
+ tabSize = Preferences.getInteger("editor.tabs.size");
+ tabString = Editor.EMPTY.substring(0, tabSize);
+ autoIndent = Preferences.getBoolean("editor.indent");
+ externalEditor = Preferences.getBoolean("editor.external");
+ }
+
+
+ //public void setExternalEditor(boolean externalEditor) {
+ //this.externalEditor = externalEditor;
+ //}
+
+
+ /**
+ * Intercepts key pressed events for JEditTextArea.
+ *
+ * Called by JEditTextArea inside processKeyEvent(). Note that this
+ * won't intercept actual characters, because those are fired on
+ * keyTyped().
+ * @return true if the event has been handled (to remove it from the queue)
+ */
+ public boolean keyPressed(KeyEvent event) {
+ // don't do things if the textarea isn't editable
+ if (externalEditor) return false;
+
+ //deselect(); // this is for paren balancing
+ char c = event.getKeyChar();
+ int code = event.getKeyCode();
+
+ //System.out.println((int)c + " " + code + " " + event);
+ //System.out.println();
+
+ Sketch sketch = editor.getSketch();
+
+ if ((event.getModifiers() & CTRL_ALT) == CTRL_ALT) {
+ if (code == KeyEvent.VK_LEFT) {
+ sketch.handlePrevCode();
+ return true;
+ } else if (code == KeyEvent.VK_RIGHT) {
+ sketch.handleNextCode();
+ return true;
+ }
+ }
+
+ if ((event.getModifiers() & KeyEvent.META_MASK) != 0) {
+ //event.consume(); // does nothing
+ return false;
+ }
+
+ // TODO i don't like these accessors. clean em up later.
+ if (!editor.getSketch().isModified()) {
+ if ((code == KeyEvent.VK_BACK_SPACE) || (code == KeyEvent.VK_TAB) ||
+ (code == KeyEvent.VK_ENTER) || ((c >= 32) && (c < 128))) {
+ sketch.setModified(true);
+ }
+ }
+
+ if ((code == KeyEvent.VK_UP) &&
+ ((event.getModifiers() & KeyEvent.CTRL_MASK) != 0)) {
+ // back up to the last empty line
+ char contents[] = textarea.getText().toCharArray();
+ //int origIndex = textarea.getCaretPosition() - 1;
+ int caretIndex = textarea.getCaretPosition();
+
+ int index = calcLineStart(caretIndex - 1, contents);
+ //System.out.println("line start " + (int) contents[index]);
+ index -= 2; // step over the newline
+ //System.out.println((int) contents[index]);
+ boolean onlySpaces = true;
+ while (index > 0) {
+ if (contents[index] == 10) {
+ if (onlySpaces) {
+ index++;
+ break;
+ } else {
+ onlySpaces = true; // reset
+ }
+ } else if (contents[index] != ' ') {
+ onlySpaces = false;
+ }
+ index--;
+ }
+ // if the first char, index will be -2
+ if (index < 0) index = 0;
+
+ if ((event.getModifiers() & KeyEvent.SHIFT_MASK) != 0) {
+ textarea.setSelectionStart(caretIndex);
+ textarea.setSelectionEnd(index);
+ } else {
+ textarea.setCaretPosition(index);
+ }
+ event.consume();
+ return true;
+
+ } else if ((code == KeyEvent.VK_DOWN) &&
+ ((event.getModifiers() & KeyEvent.CTRL_MASK) != 0)) {
+ char contents[] = textarea.getText().toCharArray();
+ int caretIndex = textarea.getCaretPosition();
+
+ int index = caretIndex;
+ int lineStart = 0;
+ boolean onlySpaces = false; // don't count this line
+ while (index < contents.length) {
+ if (contents[index] == 10) {
+ if (onlySpaces) {
+ index = lineStart; // this is it
+ break;
+ } else {
+ lineStart = index + 1;
+ onlySpaces = true; // reset
+ }
+ } else if (contents[index] != ' ') {
+ onlySpaces = false;
+ }
+ index++;
+ }
+ // if the first char, index will be -2
+ //if (index < 0) index = 0;
+
+ //textarea.setSelectionStart(index);
+ //textarea.setSelectionEnd(index);
+ if ((event.getModifiers() & KeyEvent.SHIFT_MASK) != 0) {
+ textarea.setSelectionStart(caretIndex);
+ textarea.setSelectionEnd(index);
+ } else {
+ textarea.setCaretPosition(index);
+ }
+ event.consume();
+ return true;
+ }
+
+
+ switch ((int) c) {
+
+ case 9: // TAB
+ if (textarea.isSelectionActive()) {
+ boolean outdent = (event.getModifiers() & KeyEvent.SHIFT_MASK) != 0;
+ editor.handleIndentOutdent(!outdent);
+
+ } else if (tabsExpand) { // expand tabs
+ textarea.setSelectedText(tabString);
+ event.consume();
+ return true;
+
+ } else if (tabsIndent) {
+ // this code is incomplete
+
+ // if this brace is the only thing on the line, outdent
+ //char contents[] = getCleanedContents();
+ char contents[] = textarea.getText().toCharArray();
+ // index to the character to the left of the caret
+ int prevCharIndex = textarea.getCaretPosition() - 1;
+
+ // now find the start of this line
+ int lineStart = calcLineStart(prevCharIndex, contents);
+
+ int lineEnd = lineStart;
+ while ((lineEnd < contents.length - 1) &&
+ (contents[lineEnd] != 10)) {
+ lineEnd++;
+ }
+
+ // get the number of braces, to determine whether this is an indent
+ int braceBalance = 0;
+ int index = lineStart;
+ while ((index < contents.length) &&
+ (contents[index] != 10)) {
+ if (contents[index] == '{') {
+ braceBalance++;
+ } else if (contents[index] == '}') {
+ braceBalance--;
+ }
+ index++;
+ }
+
+ // if it's a starting indent, need to ignore it, so lineStart
+ // will be the counting point. but if there's a closing indent,
+ // then the lineEnd should be used.
+ int where = (braceBalance > 0) ? lineStart : lineEnd;
+ int indent = calcBraceIndent(where, contents);
+ if (indent == -1) {
+ // no braces to speak of, do nothing
+ indent = 0;
+ } else {
+ indent += tabSize;
+ }
+
+ // and the number of spaces it has
+ int spaceCount = calcSpaceCount(prevCharIndex, contents);
+
+ textarea.setSelectionStart(lineStart);
+ textarea.setSelectionEnd(lineStart + spaceCount);
+ textarea.setSelectedText(Editor.EMPTY.substring(0, indent));
+
+ event.consume();
+ return true;
+ }
+ break;
+
+ case 10: // auto-indent
+ case 13:
+ if (autoIndent) {
+ char contents[] = textarea.getText().toCharArray();
+
+ // this is the previous character
+ // (i.e. when you hit return, it'll be the last character
+ // just before where the newline will be inserted)
+ int origIndex = textarea.getCaretPosition() - 1;
+
+ // NOTE all this cursing about CRLF stuff is probably moot
+ // NOTE since the switch to JEditTextArea, which seems to use
+ // NOTE only LFs internally (thank god). disabling for 0099.
+ // walk through the array to the current caret position,
+ // and count how many weirdo windows line endings there are,
+ // which would be throwing off the caret position number
+ /*
+ int offset = 0;
+ int realIndex = origIndex;
+ for (int i = 0; i < realIndex-1; i++) {
+ if ((contents[i] == 13) && (contents[i+1] == 10)) {
+ offset++;
+ realIndex++;
+ }
+ }
+ // back up until \r \r\n or \n.. @#($* cross platform
+ //System.out.println(origIndex + " offset = " + offset);
+ origIndex += offset; // ARGH!#(* WINDOWS#@($*
+ */
+
+ // if the previous thing is a brace (whether prev line or
+ // up farther) then the correct indent is the number of spaces
+ // on that line + 'indent'.
+ // if the previous line is not a brace, then just use the
+ // identical indentation to the previous line
+
+ // calculate the amount of indent on the previous line
+ // this will be used *only if the prev line is not an indent*
+ int spaceCount = calcSpaceCount(origIndex, contents);
+
+ // If the last character was a left curly brace, then indent.
+ // For 0122, walk backwards a bit to make sure that the there
+ // isn't a curly brace several spaces (or lines) back. Also
+ // moved this before calculating extraCount, since it'll affect
+ // that as well.
+ int index2 = origIndex;
+ while ((index2 >= 0) &&
+ Character.isWhitespace(contents[index2])) {
+ index2--;
+ }
+ if (index2 != -1) {
+ // still won't catch a case where prev stuff is a comment
+ if (contents[index2] == '{') {
+ // intermediate lines be damned,
+ // use the indent for this line instead
+ spaceCount = calcSpaceCount(index2, contents);
+ spaceCount += tabSize;
+ }
+ }
+ //System.out.println("spaceCount should be " + spaceCount);
+
+ // now before inserting this many spaces, walk forward from
+ // the caret position and count the number of spaces,
+ // so that the number of spaces aren't duplicated again
+ int index = origIndex + 1;
+ int extraCount = 0;
+ while ((index < contents.length) &&
+ (contents[index] == ' ')) {
+ //spaceCount--;
+ extraCount++;
+ index++;
+ }
+ int braceCount = 0;
+ while ((index < contents.length) && (contents[index] != '\n')) {
+ if (contents[index] == '}') {
+ braceCount++;
+ }
+ index++;
+ }
+
+ // hitting return on a line with spaces *after* the caret
+ // can cause trouble. for 0099, was ignoring the case, but this is
+ // annoying, so in 0122 we're trying to fix that.
+ /*
+ if (spaceCount - extraCount > 0) {
+ spaceCount -= extraCount;
+ }
+ */
+ spaceCount -= extraCount;
+ //if (spaceCount < 0) spaceCount = 0;
+ //System.out.println("extraCount is " + extraCount);
+
+ // now, check to see if the current line contains a } and if so,
+ // outdent again by indent
+ //if (braceCount > 0) {
+ //spaceCount -= 2;
+ //}
+
+ if (spaceCount < 0) {
+ // for rev 0122, actually delete extra space
+ //textarea.setSelectionStart(origIndex + 1);
+ textarea.setSelectionEnd(textarea.getSelectionStop() - spaceCount);
+ textarea.setSelectedText("\n");
+ } else {
+ String insertion = "\n" + Editor.EMPTY.substring(0, spaceCount);
+ textarea.setSelectedText(insertion);
+ }
+
+ // not gonna bother handling more than one brace
+ if (braceCount > 0) {
+ int sel = textarea.getSelectionStart();
+ // sel - tabSize will be -1 if start/end parens on the same line
+ // http://dev.processing.org/bugs/show_bug.cgi?id=484
+ if (sel - tabSize >= 0) {
+ textarea.select(sel - tabSize, sel);
+ String s = Editor.EMPTY.substring(0, tabSize);
+ // if these are spaces that we can delete
+ if (textarea.getSelectedText().equals(s)) {
+ textarea.setSelectedText("");
+ } else {
+ textarea.select(sel, sel);
+ }
+ }
+ }
+ } else {
+ // Enter/Return was being consumed by somehow even if false
+ // was returned, so this is a band-aid to simply fire the event again.
+ // http://dev.processing.org/bugs/show_bug.cgi?id=1073
+ textarea.setSelectedText(String.valueOf(c));
+ }
+ // mark this event as already handled (all but ignored)
+ event.consume();
+ return true;
+
+ case '}':
+ if (autoIndent) {
+ // first remove anything that was there (in case this multiple
+ // characters are selected, so that it's not in the way of the
+ // spaces for the auto-indent
+ if (textarea.getSelectionStart() != textarea.getSelectionStop()) {
+ textarea.setSelectedText("");
+ }
+
+ // if this brace is the only thing on the line, outdent
+ char contents[] = textarea.getText().toCharArray();
+ // index to the character to the left of the caret
+ int prevCharIndex = textarea.getCaretPosition() - 1;
+
+ // backup from the current caret position to the last newline,
+ // checking for anything besides whitespace along the way.
+ // if there's something besides whitespace, exit without
+ // messing any sort of indenting.
+ int index = prevCharIndex;
+ boolean finished = false;
+ while ((index != -1) && (!finished)) {
+ if (contents[index] == 10) {
+ finished = true;
+ index++;
+ } else if (contents[index] != ' ') {
+ // don't do anything, this line has other stuff on it
+ return false;
+ } else {
+ index--;
+ }
+ }
+ if (!finished) return false; // brace with no start
+ int lineStartIndex = index;
+
+ int pairedSpaceCount = calcBraceIndent(prevCharIndex, contents); //, 1);
+ if (pairedSpaceCount == -1) return false;
+
+ textarea.setSelectionStart(lineStartIndex);
+ textarea.setSelectedText(Editor.EMPTY.substring(0, pairedSpaceCount));
+
+ // mark this event as already handled
+ event.consume();
+ return true;
+ }
+ break;
+ }
+ return false;
+ }
+
+
+ public boolean keyTyped(KeyEvent event) {
+ char c = event.getKeyChar();
+
+ if ((event.getModifiers() & KeyEvent.CTRL_MASK) != 0) {
+ // on linux, ctrl-comma (prefs) being passed through to the editor
+ if (c == KeyEvent.VK_COMMA) {
+ event.consume();
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+
+ /**
+ * Return the index for the first character on this line.
+ */
+ protected int calcLineStart(int index, char contents[]) {
+ // backup from the current caret position to the last newline,
+ // so that we can figure out how far this line was indented
+ /*int spaceCount = 0;*/
+ boolean finished = false;
+ while ((index != -1) && (!finished)) {
+ if ((contents[index] == 10) ||
+ (contents[index] == 13)) {
+ finished = true;
+ //index++; // maybe ?
+ } else {
+ index--; // new
+ }
+ }
+ // add one because index is either -1 (the start of the document)
+ // or it's the newline character for the previous line
+ return index + 1;
+ }
+
+
+ /**
+ * Calculate the number of spaces on this line.
+ */
+ protected int calcSpaceCount(int index, char contents[]) {
+ index = calcLineStart(index, contents);
+
+ int spaceCount = 0;
+ // now walk forward and figure out how many spaces there are
+ while ((index < contents.length) && (index >= 0) &&
+ (contents[index++] == ' ')) {
+ spaceCount++;
+ }
+ return spaceCount;
+ }
+
+
+ /**
+ * Walk back from 'index' until the brace that seems to be
+ * the beginning of the current block, and return the number of
+ * spaces found on that line.
+ */
+ protected int calcBraceIndent(int index, char contents[]) {
+ // now that we know things are ok to be indented, walk
+ // backwards to the last { to see how far its line is indented.
+ // this isn't perfect cuz it'll pick up commented areas,
+ // but that's not really a big deal and can be fixed when
+ // this is all given a more complete (proper) solution.
+ int braceDepth = 1;
+ boolean finished = false;
+ while ((index != -1) && (!finished)) {
+ if (contents[index] == '}') {
+ // aww crap, this means we're one deeper
+ // and will have to find one more extra {
+ braceDepth++;
+ //if (braceDepth == 0) {
+ //finished = true;
+ //}
+ index--;
+ } else if (contents[index] == '{') {
+ braceDepth--;
+ if (braceDepth == 0) {
+ finished = true;
+ }
+ index--;
+ } else {
+ index--;
+ }
+ }
+ // never found a proper brace, be safe and don't do anything
+ if (!finished) return -1;
+
+ // check how many spaces on the line with the matching open brace
+ //int pairedSpaceCount = calcSpaceCount(index, contents);
+ //System.out.println(pairedSpaceCount);
+ return calcSpaceCount(index, contents);
+ }
+
+
+ /**
+ * Get the character array and blank out the commented areas.
+ * This hasn't yet been tested, the plan was to make auto-indent
+ * less gullible (it gets fooled by braces that are commented out).
+ */
+ protected char[] getCleanedContents() {
+ char c[] = textarea.getText().toCharArray();
+
+ int index = 0;
+ while (index < c.length - 1) {
+ if ((c[index] == '/') && (c[index+1] == '*')) {
+ c[index++] = 0;
+ c[index++] = 0;
+ while ((index < c.length - 1) &&
+ !((c[index] == '*') && (c[index+1] == '/'))) {
+ c[index++] = 0;
+ }
+
+ } else if ((c[index] == '/') && (c[index+1] == '/')) {
+ // clear out until the end of the line
+ while ((index < c.length) && (c[index] != 10)) {
+ c[index++] = 0;
+ }
+ if (index != c.length) {
+ index++; // skip over the newline
+ }
+ }
+ }
+ return c;
+ }
+
+ /*
+ protected char[] getCleanedContents() {
+ char c[] = textarea.getText().toCharArray();
+ boolean insideMulti; // multi-line comment
+ boolean insideSingle; // single line double slash
+
+ //for (int i = 0; i < c.length - 1; i++) {
+ int index = 0;
+ while (index < c.length - 1) {
+ if (insideMulti && (c[index] == '*') && (c[index+1] == '/')) {
+ insideMulti = false;
+ index += 2;
+ } else if ((c[index] == '/') && (c[index+1] == '*')) {
+ insideMulti = true;
+ index += 2;
+ } else if ((c[index] == '/') && (c[index+1] == '/')) {
+ // clear out until the end of the line
+ while (c[index] != 10) {
+ c[index++] = 0;
+ }
+ index++;
+ }
+ }
+ }
+ */
+}
diff --git a/app/src/processing/app/EditorStatus.java b/app/src/processing/app/EditorStatus.java
new file mode 100644
index 000000000..a7035ab7c
--- /dev/null
+++ b/app/src/processing/app/EditorStatus.java
@@ -0,0 +1,431 @@
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+/*
+ Part of the Processing project - http://processing.org
+
+ Copyright (c) 2004-08 Ben Fry and Casey Reas
+ Copyright (c) 2001-04 Massachusetts Institute of Technology
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+package processing.app;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+
+
+/**
+ * Panel just below the editing area that contains status messages.
+ */
+public class EditorStatus extends JPanel /*implements ActionListener*/ {
+ static Color bgcolor[];
+ static Color fgcolor[];
+
+ static final int NOTICE = 0;
+ static final int ERR = 1;
+ //static final int PROMPT = 2;
+ //static final int EDIT = 3;
+ static final int EDIT = 2;
+
+ static final int YES = 1;
+ static final int NO = 2;
+ static final int CANCEL = 3;
+ static final int OK = 4;
+
+ static final String NO_MESSAGE = "";
+
+ Editor editor;
+
+ int mode;
+ String message;
+
+ Font font;
+ FontMetrics metrics;
+ int ascent;
+
+ Image offscreen;
+ int sizeW, sizeH;
+ int imageW, imageH;
+
+ //JButton yesButton;
+ //JButton noButton;
+ JButton cancelButton;
+ JButton okButton;
+ JTextField editField;
+
+ //Thread promptThread;
+ int response;
+
+
+ public EditorStatus(Editor editor) {
+ this.editor = editor;
+ empty();
+
+ if (bgcolor == null) {
+ bgcolor = new Color[3]; //4];
+ bgcolor[0] = Theme.getColor("status.notice.bgcolor");
+ bgcolor[1] = Theme.getColor("status.error.bgcolor");
+ bgcolor[2] = Theme.getColor("status.edit.bgcolor");
+
+ fgcolor = new Color[3]; //4];
+ fgcolor[0] = Theme.getColor("status.notice.fgcolor");
+ fgcolor[1] = Theme.getColor("status.error.fgcolor");
+ fgcolor[2] = Theme.getColor("status.edit.fgcolor");
+ }
+ }
+
+
+ public void empty() {
+ mode = NOTICE;
+ message = NO_MESSAGE;
+ //update();
+ repaint();
+ }
+
+
+ public void notice(String message) {
+ mode = NOTICE;
+ this.message = message;
+ //update();
+ repaint();
+ }
+
+ public void unnotice(String unmessage) {
+ if (message.equals(unmessage)) empty();
+ }
+
+
+ public void error(String message) {
+ mode = ERR;
+ this.message = message;
+ repaint();
+ }
+
+
+ /*
+ public void prompt(String message) {
+ mode = PROMPT;
+ this.message = message;
+
+ response = 0;
+ yesButton.setVisible(true);
+ noButton.setVisible(true);
+ cancelButton.setVisible(true);
+ yesButton.requestFocus();
+
+ repaint();
+ }
+
+
+ // prompt has been handled, re-hide the buttons
+ public void unprompt() {
+ yesButton.setVisible(false);
+ noButton.setVisible(false);
+ cancelButton.setVisible(false);
+ empty();
+ }
+ */
+
+
+ public void edit(String message, String dflt) {
+ mode = EDIT;
+ this.message = message;
+
+ response = 0;
+ okButton.setVisible(true);
+ cancelButton.setVisible(true);
+ editField.setVisible(true);
+ editField.setText(dflt);
+ editField.selectAll();
+ editField.requestFocus();
+
+ repaint();
+ }
+
+ public void unedit() {
+ okButton.setVisible(false);
+ cancelButton.setVisible(false);
+ editField.setVisible(false);
+ empty();
+ }
+
+
+ /*
+ public void update() {
+ Graphics g = this.getGraphics();
+ try {
+ setBackground(bgcolor[mode]);
+ } catch (NullPointerException e) { } // if not ready yet
+ if (g != null) paint(g);
+ }
+
+ public void update(Graphics g) {
+ paint(g);
+ }
+ */
+
+
+ public void paintComponent(Graphics screen) {
+ //if (screen == null) return;
+ if (okButton == null) setup();
+
+ //System.out.println("status.paintComponent");
+
+ Dimension size = getSize();
+ if ((size.width != sizeW) || (size.height != sizeH)) {
+ // component has been resized
+
+ if ((size.width > imageW) || (size.height > imageH)) {
+ // nix the image and recreate, it's too small
+ offscreen = null;
+
+ } else {
+ // who cares, just resize
+ sizeW = size.width;
+ sizeH = size.height;
+ setButtonBounds();
+ }
+ }
+
+ if (offscreen == null) {
+ sizeW = size.width;
+ sizeH = size.height;
+ setButtonBounds();
+ imageW = sizeW;
+ imageH = sizeH;
+ offscreen = createImage(imageW, imageH);
+ }
+
+ Graphics g = offscreen.getGraphics();
+ if (font == null) {
+ font = Theme.getFont("status.font");
+ //new Font("SansSerif", Font.PLAIN, 12));
+ g.setFont(font);
+ metrics = g.getFontMetrics();
+ ascent = metrics.getAscent();
+ }
+
+ //setBackground(bgcolor[mode]); // does nothing
+
+ g.setColor(bgcolor[mode]);
+ g.fillRect(0, 0, imageW, imageH);
+
+ g.setColor(fgcolor[mode]);
+ g.setFont(font); // needs to be set each time on osx
+ g.drawString(message, Preferences.GUI_SMALL, (sizeH + ascent) / 2);
+
+ screen.drawImage(offscreen, 0, 0, null);
+ }
+
+
+ protected void setup() {
+ if (okButton == null) {
+ cancelButton = new JButton(Preferences.PROMPT_CANCEL);
+ okButton = new JButton(Preferences.PROMPT_OK);
+
+ cancelButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ if (mode == EDIT) {
+ unedit();
+ //editor.toolbar.clear();
+ }
+ }
+ });
+
+ okButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ // answering to rename/new code question
+ if (mode == EDIT) { // this if() isn't (shouldn't be?) necessary
+ String answer = editField.getText();
+ editor.getSketch().nameCode(answer);
+ unedit();
+ }
+ }
+ });
+
+ // !@#(* aqua ui #($*(( that turtle-neck wearing #(** (#$@)(
+ // os9 seems to work if bg of component is set, but x still a bastard
+ if (Base.isMacOS()) {
+ //yesButton.setBackground(bgcolor[EDIT]);
+ //noButton.setBackground(bgcolor[EDIT]);
+ cancelButton.setBackground(bgcolor[EDIT]);
+ okButton.setBackground(bgcolor[EDIT]);
+ }
+ setLayout(null);
+
+ /*
+ yesButton.addActionListener(this);
+ noButton.addActionListener(this);
+ cancelButton.addActionListener(this);
+ okButton.addActionListener(this);
+ */
+
+ //add(yesButton);
+ //add(noButton);
+ add(cancelButton);
+ add(okButton);
+
+ //yesButton.setVisible(false);
+ //noButton.setVisible(false);
+ cancelButton.setVisible(false);
+ okButton.setVisible(false);
+
+ editField = new JTextField();
+ // disabling, was not in use
+ //editField.addActionListener(this);
+
+ //if (Base.platform != Base.MACOSX) {
+ editField.addKeyListener(new KeyAdapter() {
+
+ // Grab ESC with keyPressed, because it's not making it to keyTyped
+ public void keyPressed(KeyEvent event) {
+ if (event.getKeyChar() == KeyEvent.VK_ESCAPE) {
+ unedit();
+ //editor.toolbar.clear();
+ event.consume();
+ }
+ }
+
+ // use keyTyped to catch when the feller is actually
+ // added to the text field. with keyTyped, as opposed to
+ // keyPressed, the keyCode will be zero, even if it's
+ // enter or backspace or whatever, so the keychar should
+ // be used instead. grr.
+ public void keyTyped(KeyEvent event) {
+ //System.out.println("got event " + event);
+ int c = event.getKeyChar();
+
+ if (c == KeyEvent.VK_ENTER) { // accept the input
+ String answer = editField.getText();
+ editor.getSketch().nameCode(answer);
+ unedit();
+ event.consume();
+
+ // easier to test the affirmative case than the negative
+ } else if ((c == KeyEvent.VK_BACK_SPACE) ||
+ (c == KeyEvent.VK_DELETE) ||
+ (c == KeyEvent.VK_RIGHT) ||
+ (c == KeyEvent.VK_LEFT) ||
+ (c == KeyEvent.VK_UP) ||
+ (c == KeyEvent.VK_DOWN) ||
+ (c == KeyEvent.VK_HOME) ||
+ (c == KeyEvent.VK_END) ||
+ (c == KeyEvent.VK_SHIFT)) {
+ // these events are ignored
+
+ /*
+ } else if (c == KeyEvent.VK_ESCAPE) {
+ unedit();
+ editor.toolbar.clear();
+ event.consume();
+ */
+
+ } else if (c == KeyEvent.VK_SPACE) {
+ String t = editField.getText();
+ int start = editField.getSelectionStart();
+ int end = editField.getSelectionEnd();
+ editField.setText(t.substring(0, start) + "_" +
+ t.substring(end));
+ editField.setCaretPosition(start+1);
+ event.consume();
+
+ } else if ((c == '_') || (c == '.') || // allow .pde and .java
+ ((c >= 'A') && (c <= 'Z')) ||
+ ((c >= 'a') && (c <= 'z'))) {
+ // these are ok, allow them through
+
+ } else if ((c >= '0') && (c <= '9')) {
+ // getCaretPosition == 0 means that it's the first char
+ // and the field is empty.
+ // getSelectionStart means that it *will be* the first
+ // char, because the selection is about to be replaced
+ // with whatever is typed.
+ if ((editField.getCaretPosition() == 0) ||
+ (editField.getSelectionStart() == 0)) {
+ // number not allowed as first digit
+ //System.out.println("bad number bad");
+ event.consume();
+ }
+ } else {
+ event.consume();
+ //System.out.println("code is " + code + " char = " + c);
+ }
+ //System.out.println("code is " + code + " char = " + c);
+ }
+ });
+ add(editField);
+ editField.setVisible(false);
+ }
+ }
+
+
+ protected void setButtonBounds() {
+ int top = (sizeH - Preferences.BUTTON_HEIGHT) / 2;
+ int eachButton = Preferences.GUI_SMALL + Preferences.BUTTON_WIDTH;
+
+ int cancelLeft = sizeW - eachButton;
+ int noLeft = cancelLeft - eachButton;
+ int yesLeft = noLeft - eachButton;
+
+ //yesButton.setLocation(yesLeft, top);
+ //noButton.setLocation(noLeft, top);
+ cancelButton.setLocation(cancelLeft, top);
+ okButton.setLocation(noLeft, top);
+
+ //yesButton.setSize(Preferences.BUTTON_WIDTH, Preferences.BUTTON_HEIGHT);
+ //noButton.setSize(Preferences.BUTTON_WIDTH, Preferences.BUTTON_HEIGHT);
+ cancelButton.setSize(Preferences.BUTTON_WIDTH, Preferences.BUTTON_HEIGHT);
+ okButton.setSize(Preferences.BUTTON_WIDTH, Preferences.BUTTON_HEIGHT);
+
+ // edit field height is awkward, and very different between mac and pc,
+ // so use at least the preferred height for now.
+ int editWidth = 2*Preferences.BUTTON_WIDTH;
+ int editHeight = editField.getPreferredSize().height;
+ int editTop = (1 + sizeH - editHeight) / 2; // add 1 for ceil
+ editField.setBounds(yesLeft - Preferences.BUTTON_WIDTH, editTop,
+ editWidth, editHeight);
+ }
+
+
+ public Dimension getPreferredSize() {
+ return getMinimumSize();
+ }
+
+ public Dimension getMinimumSize() {
+ return new Dimension(300, Preferences.GRID_SIZE);
+ }
+
+ public Dimension getMaximumSize() {
+ return new Dimension(3000, Preferences.GRID_SIZE);
+ }
+
+
+ public void actionPerformed(ActionEvent e) {
+ if (e.getSource() == cancelButton) {
+ if (mode == EDIT) unedit();
+ //editor.toolbar.clear();
+
+ } else if (e.getSource() == okButton) {
+ // answering to rename/new code question
+ if (mode == EDIT) { // this if() isn't (shouldn't be?) necessary
+ String answer = editField.getText();
+ editor.getSketch().nameCode(answer);
+ unedit();
+ }
+ }
+ }
+}
diff --git a/app/src/processing/app/EditorToolbar.java b/app/src/processing/app/EditorToolbar.java
new file mode 100644
index 000000000..f7bf14569
--- /dev/null
+++ b/app/src/processing/app/EditorToolbar.java
@@ -0,0 +1,447 @@
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+/*
+ Part of the Processing project - http://processing.org
+
+ Copyright (c) 2004-08 Ben Fry and Casey Reas
+ Copyright (c) 2001-04 Massachusetts Institute of Technology
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+package processing.app;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.event.*;
+
+
+/**
+ * run/stop/etc buttons for the ide
+ */
+public class EditorToolbar extends JComponent implements MouseInputListener {
+
+ static final String title[] = {
+ "Run", "Stop", "New", "Open", "Save", "Export"
+ };
+
+ static final int BUTTON_COUNT = title.length;
+ /** Width of each toolbar button. */
+ static final int BUTTON_WIDTH = 27;
+ /** Height of each toolbar button. */
+ static final int BUTTON_HEIGHT = 32;
+ /** The amount of space between groups of buttons on the toolbar. */
+ static final int BUTTON_GAP = 5;
+
+ static final int RUN = 0;
+ static final int STOP = 1;
+
+ static final int NEW = 2;
+ static final int OPEN = 3;
+ static final int SAVE = 4;
+ static final int EXPORT = 5;
+
+ static final int INACTIVE = 0;
+ static final int ROLLOVER = 1;
+ static final int ACTIVE = 2;
+
+ Editor editor;
+ //boolean disableRun; // this was for library
+ //Label status;
+
+ Image offscreen;
+ int width, height;
+
+ Color bgcolor;
+
+ static Image buttons;
+ static Image inactive[];
+ static Image rollover[];
+ static Image active[];
+ int currentRollover;
+ //int currentSelection;
+
+ JPopupMenu popup;
+ JMenu menu;
+
+ int buttonCount;
+ int state[] = new int[BUTTON_COUNT];
+ Image stateImage[];
+ int which[]; // mapping indices to implementation
+
+ int x1[], x2[];
+ int y1, y2;
+
+ String status;
+ Font statusFont;
+ Color statusColor;
+
+
+ public EditorToolbar(Editor editor, JMenu menu) {
+ this.editor = editor;
+ this.menu = menu;
+
+ if (buttons == null) {
+ buttons = Base.getThemeImage("buttons.gif", this);
+ }
+
+ buttonCount = 0;
+ which = new int[BUTTON_COUNT];
+
+ //which[buttonCount++] = NOTHING;
+ which[buttonCount++] = RUN;
+ which[buttonCount++] = STOP;
+ which[buttonCount++] = NEW;
+ which[buttonCount++] = OPEN;
+ which[buttonCount++] = SAVE;
+ which[buttonCount++] = EXPORT;
+
+ currentRollover = -1;
+
+ bgcolor = Theme.getColor("buttons.bgcolor");
+
+ status = "";
+
+ statusFont = Theme.getFont("buttons.status.font");
+ statusColor = Theme.getColor("buttons.status.color");
+
+ addMouseListener(this);
+ addMouseMotionListener(this);
+ }
+
+
+ public void paintComponent(Graphics screen) {
+ // this data is shared by all EditorToolbar instances
+ if (inactive == null) {
+ inactive = new Image[BUTTON_COUNT];
+ rollover = new Image[BUTTON_COUNT];
+ active = new Image[BUTTON_COUNT];
+
+ int IMAGE_SIZE = 33;
+
+ for (int i = 0; i < BUTTON_COUNT; i++) {
+ inactive[i] = createImage(BUTTON_WIDTH, BUTTON_HEIGHT);
+ Graphics g = inactive[i].getGraphics();
+ g.drawImage(buttons, -(i*IMAGE_SIZE) - 3, -2*IMAGE_SIZE, null);
+
+ rollover[i] = createImage(BUTTON_WIDTH, BUTTON_HEIGHT);
+ g = rollover[i].getGraphics();
+ g.drawImage(buttons, -(i*IMAGE_SIZE) - 3, -1*IMAGE_SIZE, null);
+
+ active[i] = createImage(BUTTON_WIDTH, BUTTON_HEIGHT);
+ g = active[i].getGraphics();
+ g.drawImage(buttons, -(i*IMAGE_SIZE) - 3, -0*IMAGE_SIZE, null);
+ }
+ }
+
+ // this happens once per instance of EditorToolbar
+ if (stateImage == null) {
+ state = new int[buttonCount];
+ stateImage = new Image[buttonCount];
+ for (int i = 0; i < buttonCount; i++) {
+ setState(i, INACTIVE, false);
+ }
+ y1 = 0;
+ y2 = BUTTON_HEIGHT;
+ x1 = new int[buttonCount];
+ x2 = new int[buttonCount];
+ }
+
+ Dimension size = getSize();
+ if ((offscreen == null) ||
+ (size.width != width) || (size.height != height)) {
+ offscreen = createImage(size.width, size.height);
+ width = size.width;
+ height = size.height;
+
+ int offsetX = 3;
+ for (int i = 0; i < buttonCount; i++) {
+ x1[i] = offsetX;
+ if (i == 2) x1[i] += BUTTON_GAP;
+ x2[i] = x1[i] + BUTTON_WIDTH;
+ offsetX = x2[i];
+ }
+ }
+ Graphics g = offscreen.getGraphics();
+ g.setColor(bgcolor); //getBackground());
+ g.fillRect(0, 0, width, height);
+
+ for (int i = 0; i < buttonCount; i++) {
+ g.drawImage(stateImage[i], x1[i], y1, null);
+ }
+
+ g.setColor(statusColor);
+ g.setFont(statusFont);
+
+ /*
+ // if i ever find the guy who wrote the java2d api, i will hurt him.
+ Graphics2D g2 = (Graphics2D) g;
+ FontRenderContext frc = g2.getFontRenderContext();
+ float statusW = (float) statusFont.getStringBounds(status, frc).getWidth();
+ float statusX = (getSize().width - statusW) / 2;
+ g2.drawString(status, statusX, statusY);
+ */
+ //int statusY = (BUTTON_HEIGHT + statusFont.getAscent()) / 2;
+ int statusY = (BUTTON_HEIGHT + g.getFontMetrics().getAscent()) / 2;
+ g.drawString(status, buttonCount * BUTTON_WIDTH + 3 * BUTTON_GAP, statusY);
+
+ screen.drawImage(offscreen, 0, 0, null);
+ }
+
+
+ public void mouseMoved(MouseEvent e) {
+ // mouse events before paint();
+ if (state == null) return;
+
+ if (state[OPEN] != INACTIVE) {
+ // avoid flicker, since there will probably be an update event
+ setState(OPEN, INACTIVE, false);
+ }
+ //System.out.println(e);
+ //mouseMove(e);
+ handleMouse(e.getX(), e.getY());
+ }
+
+
+ public void mouseDragged(MouseEvent e) { }
+
+
+ public void handleMouse(int x, int y) {
+ if (currentRollover != -1) {
+ if ((x > x1[currentRollover]) && (y > y1) &&
+ (x < x2[currentRollover]) && (y < y2)) {
+ return;
+
+ } else {
+ setState(currentRollover, INACTIVE, true);
+ messageClear(title[currentRollover]);
+ currentRollover = -1;
+ }
+ }
+ int sel = findSelection(x, y);
+ if (sel == -1) return;
+
+ if (state[sel] != ACTIVE) {
+ //if (!(disableRun && ((sel == RUN) || (sel == STOP)))) {
+ setState(sel, ROLLOVER, true);
+ currentRollover = sel;
+ //}
+ }
+ }
+
+
+ private int findSelection(int x, int y) {
+ // if app loads slowly and cursor is near the buttons
+ // when it comes up, the app may not have time to load
+ if ((x1 == null) || (x2 == null)) return -1;
+
+ for (int i = 0; i < buttonCount; i++) {
+ if ((y > y1) && (x > x1[i]) &&
+ (y < y2) && (x < x2[i])) {
+ //System.out.println("sel is " + i);
+ return i;
+ }
+ }
+ return -1;
+ }
+
+
+ private void setState(int slot, int newState, boolean updateAfter) {
+ //if (inactive == null) return;
+ state[slot] = newState;
+ switch (newState) {
+ case INACTIVE:
+ stateImage[slot] = inactive[which[slot]];
+ break;
+ case ACTIVE:
+ stateImage[slot] = active[which[slot]];
+ break;
+ case ROLLOVER:
+ stateImage[slot] = rollover[which[slot]];
+ message(title[which[slot]]);
+ break;
+ }
+ if (updateAfter) {
+ //System.out.println("trying to update " + slot + " " + state[slot]);
+ //new Exception("setting slot " + slot + " to " + state[slot]).printStackTrace();
+ repaint(); // changed for swing from update();
+ //Toolkit.getDefaultToolkit().sync();
+ }
+ }
+
+
+ public void mouseEntered(MouseEvent e) {
+ //mouseMove(e);
+ handleMouse(e.getX(), e.getY());
+ }
+
+
+ public void mouseExited(MouseEvent e) {
+ // if the popup menu for is visible, don't register this,
+ // because the popup being set visible will fire a mouseExited() event
+ if ((popup != null) && popup.isVisible()) return;
+
+ if (state[OPEN] != INACTIVE) {
+ setState(OPEN, INACTIVE, true);
+ }
+ status = "";
+ handleMouse(e.getX(), e.getY());
+ }
+
+ int wasDown = -1;
+
+
+ public void mousePressed(MouseEvent e) {
+ final int x = e.getX();
+ final int y = e.getY();
+
+ int sel = findSelection(x, y);
+ ///if (sel == -1) return false;
+ if (sel == -1) return;
+ currentRollover = -1;
+
+ switch (sel) {
+ case RUN:
+ editor.handleRun(e.isShiftDown());
+ break;
+
+ case STOP:
+ editor.handleStop();
+ break;
+
+ case OPEN:
+ popup = menu.getPopupMenu();
+ popup.show(EditorToolbar.this, x, y);
+ break;
+
+ case NEW:
+ //editor.base.handleNew(e.isShiftDown());
+ editor.base.handleNewReplace();
+ break;
+
+ case SAVE:
+ editor.handleSave(false);
+ break;
+
+ case EXPORT:
+ if (e.isShiftDown()) {
+ editor.handleExportApplication();
+ } else {
+ editor.handleExport();
+ }
+ break;
+ }
+ }
+
+
+ public void mouseClicked(MouseEvent e) { }
+
+
+ public void mouseReleased(MouseEvent e) {
+ /*
+ switch (currentSelection) {
+
+ case OPEN:
+ setState(OPEN, INACTIVE, true);
+ break;
+ }
+ currentSelection = -1;
+ */
+ }
+
+
+ //public void disableRun(boolean what) {
+ //disableRun = what;
+ //}
+
+
+ /*
+ public void run() {
+ if (inactive == null) return;
+ clear();
+ setState(RUN, ACTIVE, true);
+ }
+ */
+
+// public void running(boolean yesno) {
+// setState(RUN, yesno ? ACTIVE : INACTIVE, true);
+// }
+
+
+ /**
+ * Set a particular button to be active.
+ */
+ public void activate(int what) {
+ //System.out.println("activating " + what);
+ if (inactive == null) return;
+ setState(what, ACTIVE, true);
+ }
+
+ //public void clearRun() {
+ //if (inactive == null) return;
+ //setState(RUN, INACTIVE, true);
+ //}
+
+
+ /**
+ * Set a particular button to be active.
+ */
+ public void deactivate(int what) {
+ if (inactive == null) return; // don't draw if not ready
+ setState(what, INACTIVE, true);
+ }
+
+ /**
+ * Clear all the state of all buttons.
+ */
+// public void clear() { // (int button) {
+// if (inactive == null) return;
+//
+// System.out.println("clearing state of buttons");
+// // skip the run button, do the others
+// for (int i = 1; i < buttonCount; i++) {
+// setState(i, INACTIVE, false);
+// }
+// repaint(); // changed for swing from update();
+// }
+
+
+ public void message(String msg) {
+ //status.setText(msg + " "); // don't mind the hack
+ status = msg;
+ }
+
+
+ public void messageClear(String msg) {
+ //if (status.getText().equals(msg + " ")) status.setText(Editor.EMPTY);
+ if (status.equals(msg)) status = "";
+ }
+
+
+ public Dimension getPreferredSize() {
+ return getMinimumSize();
+ }
+
+
+ public Dimension getMinimumSize() {
+ return new Dimension((BUTTON_COUNT + 1)*BUTTON_WIDTH, BUTTON_HEIGHT);
+ }
+
+
+ public Dimension getMaximumSize() {
+ return new Dimension(3000, BUTTON_HEIGHT);
+ }
+}
diff --git a/app/src/processing/app/FindReplace.java b/app/src/processing/app/FindReplace.java
new file mode 100644
index 000000000..112eca3ad
--- /dev/null
+++ b/app/src/processing/app/FindReplace.java
@@ -0,0 +1,350 @@
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+/*
+ Part of the Processing project - http://processing.org
+
+ Copyright (c) 2004-08 Ben Fry and Casey Reas
+ Copyright (c) 2001-04 Massachusetts Institute of Technology
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+package processing.app;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+
+
+/**
+ * Find & Replace window for the Processing editor.
+ *
+ * One major annoyance in this is that the window is re-created each time
+ * that "Find" is called. This is because Mac OS X has a strange focus
+ * issue with windows that are re-shown with setVisible() or show().
+ * requestFocusInWindow() properly sets the focus to the find field,
+ * however, just a short moment later, the focus is set to null. Even
+ * trying to catch this scenario and request it again doesn't seem to work.
+ * Most likely this is some annoyance buried deep in one of Apple's docs,
+ * or in the doc for the focus stuff (I tend to think the former because
+ * Windows doesn't seem to be quite so beligerent). Filed as
+ * Bug 244
+ * should anyone have clues about how to fix.
+ */
+public class FindReplace extends JFrame implements ActionListener {
+
+ static final int BIG = 13;
+ static final int SMALL = 6;
+
+ Editor editor;
+
+ JTextField findField;
+ JTextField replaceField;
+ static String findString;
+ static String replaceString;
+
+ JButton replaceButton;
+ JButton replaceAllButton;
+ JButton replaceFindButton;
+ JButton findButton;
+
+ JCheckBox ignoreCaseBox;
+ static boolean ignoreCase = true;
+
+ /// true when there's something selected in the editor
+ boolean found;
+
+
+ public FindReplace(Editor editor) {
+ super("Find");
+ setResizable(false);
+ this.editor = editor;
+
+ Container pain = getContentPane();
+ pain.setLayout(null);
+
+ JLabel findLabel = new JLabel("Find:");
+ Dimension d0 = findLabel.getPreferredSize();
+ JLabel replaceLabel = new JLabel("Replace with:");
+ Dimension d1 = replaceLabel.getPreferredSize();
+
+ pain.add(findLabel);
+ pain.add(replaceLabel);
+
+ pain.add(findField = new JTextField(20));
+ pain.add(replaceField = new JTextField(20));
+ Dimension d2 = findField.getPreferredSize();
+
+ if (findString != null) findField.setText(findString);
+ if (replaceString != null) replaceField.setText(replaceString);
+ //System.out.println("setting find str to " + findString);
+ //findField.requestFocusInWindow();
+
+ //pain.setDefault
+ /*
+ findField.addFocusListener(new FocusListener() {
+ public void focusGained(FocusEvent e) {
+ System.out.println("Focus gained " + e.getOppositeComponent());
+ }
+
+ public void focusLost(FocusEvent e) {
+ System.out.println("Focus lost "); // + e.getOppositeComponent());
+ if (e.getOppositeComponent() == null) {
+ requestFocusInWindow();
+ }
+ }
+ });
+ */
+
+ // +1 since it's better to tend downwards
+ int yoff = (1 + d2.height - d1.height) / 2;
+
+ findLabel.setBounds(BIG + (d1.width-d0.width) + yoff, BIG,
+ d1.width, d1.height);
+ replaceLabel.setBounds(BIG, BIG + d2.height + SMALL + yoff,
+ d1.width, d1.height);
+
+ //ignoreCase = true;
+ ignoreCaseBox = new JCheckBox("Ignore Case");
+ ignoreCaseBox.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ ignoreCase = ignoreCaseBox.isSelected();
+ }
+ });
+ ignoreCaseBox.setSelected(ignoreCase);
+ pain.add(ignoreCaseBox);
+
+ //
+
+ JPanel buttons = new JPanel();
+ buttons.setLayout(new FlowLayout());
+
+ // ordering is different on mac versus pc
+ if (Base.isMacOS()) {
+ buttons.add(replaceAllButton = new JButton("Replace All"));
+ buttons.add(replaceButton = new JButton("Replace"));
+ buttons.add(replaceFindButton = new JButton("Replace & Find"));
+ buttons.add(findButton = new JButton("Find"));
+
+ } else {
+ buttons.add(findButton = new JButton("Find"));
+ buttons.add(replaceFindButton = new JButton("Replace & Find"));
+ buttons.add(replaceButton = new JButton("Replace"));
+ buttons.add(replaceAllButton = new JButton("Replace All"));
+ }
+ pain.add(buttons);
+
+ // to fix ugliness.. normally macosx java 1.3 puts an
+ // ugly white border around this object, so turn it off.
+ if (Base.isMacOS()) {
+ buttons.setBorder(null);
+ }
+
+ Dimension d3 = buttons.getPreferredSize();
+ //buttons.setBounds(BIG, BIG + d2.height*2 + SMALL + BIG,
+ buttons.setBounds(BIG, BIG + d2.height*3 + SMALL*2 + BIG,
+ d3.width, d3.height);
+
+ //
+
+ findField.setBounds(BIG + d1.width + SMALL, BIG,
+ d3.width - (d1.width + SMALL), d2.height);
+ replaceField.setBounds(BIG + d1.width + SMALL, BIG + d2.height + SMALL,
+ d3.width - (d1.width + SMALL), d2.height);
+
+ ignoreCaseBox.setBounds(BIG + d1.width + SMALL,
+ BIG + d2.height*2 + SMALL*2,
+ d3.width, d2.height);
+
+ //
+
+ replaceButton.addActionListener(this);
+ replaceAllButton.addActionListener(this);
+ replaceFindButton.addActionListener(this);
+ findButton.addActionListener(this);
+
+ // you mustn't replace what you haven't found, my son
+ replaceButton.setEnabled(false);
+ replaceFindButton.setEnabled(false);
+
+ // so that typing will go straight to this field
+ //findField.requestFocus();
+
+ // make the find button the blinky default
+ getRootPane().setDefaultButton(findButton);
+
+ Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
+
+ int wide = d3.width + BIG*2;
+ Rectangle butt = buttons.getBounds(); // how big is your butt?
+ int high = butt.y + butt.height + BIG*2 + SMALL;
+
+ setBounds((screen.width - wide) / 2,
+ (screen.height - high) / 2, wide, high);
+
+ setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
+ addWindowListener(new WindowAdapter() {
+ public void windowClosing(WindowEvent e) {
+ handleClose();
+ }
+ });
+ Base.registerWindowCloseKeys(getRootPane(), new ActionListener() {
+ public void actionPerformed(ActionEvent actionEvent) {
+ //hide();
+ handleClose();
+ }
+ });
+ Base.setIcon(this);
+
+ // hack to to get first field to focus properly on osx
+ addWindowListener(new WindowAdapter() {
+ public void windowActivated(WindowEvent e) {
+ //System.out.println("activating");
+ /*boolean ok =*/ findField.requestFocusInWindow();
+ //System.out.println("got " + ok);
+ findField.selectAll();
+ }
+ });
+ }
+
+
+ public void handleClose() {
+ //System.out.println("handling close now");
+ findString = findField.getText();
+ replaceString = replaceField.getText();
+
+ // this object should eventually become dereferenced
+ setVisible(false);
+ }
+
+
+ /*
+ public void show() {
+ findField.requestFocusInWindow();
+ super.show();
+ //findField.selectAll();
+ //findField.requestFocus();
+ }
+ */
+
+
+ public void actionPerformed(ActionEvent e) {
+ Object source = e.getSource();
+
+ if (source == findButton) {
+ find(true);
+
+ } else if (source == replaceFindButton) {
+ replace();
+ find(true);
+
+ } else if (source == replaceButton) {
+ replace();
+
+ } else if (source == replaceAllButton) {
+ replaceAll();
+ }
+ }
+
+
+ // look for the next instance of the find string
+ // to be found later than the current caret selection
+
+ // once found, select it (and go to that line)
+
+ public void find(boolean wrap) {
+ // in case search len is zero,
+ // otherwise replace all will go into an infinite loop
+ found = false;
+
+ String search = findField.getText();
+ //System.out.println("finding for " + search + " " + findString);
+ // this will catch "find next" being called when no search yet
+ if (search.length() == 0) return;
+
+ String text = editor.getText();
+
+ if (ignoreCase) {
+ search = search.toLowerCase();
+ text = text.toLowerCase();
+ }
+
+ //int selectionStart = editor.textarea.getSelectionStart();
+ int selectionEnd = editor.getSelectionStop();
+
+ int nextIndex = text.indexOf(search, selectionEnd);
+ if (nextIndex == -1) {
+ if (wrap) {
+ // if wrapping, a second chance is ok, start from beginning
+ nextIndex = text.indexOf(search, 0);
+ }
+
+ if (nextIndex == -1) {
+ found = false;
+ replaceButton.setEnabled(false);
+ replaceFindButton.setEnabled(false);
+ //Toolkit.getDefaultToolkit().beep();
+ return;
+ }
+ }
+ found = true;
+ replaceButton.setEnabled(true);
+ replaceFindButton.setEnabled(true);
+ editor.setSelection(nextIndex, nextIndex + search.length());
+ }
+
+
+ /**
+ * Replace the current selection with whatever's in the
+ * replacement text field.
+ */
+ public void replace() {
+ if (!found) return; // don't replace if nothing found
+
+ // check to see if the document has wrapped around
+ // otherwise this will cause an infinite loop
+ String sel = editor.getSelectedText();
+ if (sel.equals(replaceField.getText())) {
+ found = false;
+ replaceButton.setEnabled(false);
+ replaceFindButton.setEnabled(false);
+ return;
+ }
+
+ editor.setSelectedText(replaceField.getText());
+ //editor.setSketchModified(true);
+ //editor.sketch.setCurrentModified(true);
+ editor.getSketch().setModified(true); // TODO is this necessary?
+
+ // don't allow a double replace
+ replaceButton.setEnabled(false);
+ replaceFindButton.setEnabled(false);
+ }
+
+
+ /**
+ * Replace everything that matches by doing find and replace
+ * alternately until nothing more found.
+ */
+ public void replaceAll() {
+ // move to the beginning
+ editor.setSelection(0, 0);
+
+ do {
+ find(false);
+ replace();
+ } while (found);
+ }
+}
diff --git a/app/src/processing/app/Platform.java b/app/src/processing/app/Platform.java
new file mode 100644
index 000000000..ef03f56ce
--- /dev/null
+++ b/app/src/processing/app/Platform.java
@@ -0,0 +1,139 @@
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+/*
+ Part of the Processing project - http://processing.org
+
+ Copyright (c) 2008 Ben Fry and Casey Reas
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+package processing.app;
+
+import java.io.File;
+
+import javax.swing.UIManager;
+
+
+/**
+ * Used by Base for platform-specific tweaking, for instance finding the
+ * sketchbook location using the Windows registry, or OS X event handling.
+ *
+ * The methods in this implementation are used by default, and can be
+ * overridden by a subclass, if loaded by Base.main().
+ *
+ * These methods throw vanilla-flavored Exceptions, so that error handling
+ * occurs inside Base.
+ *
+ * There is currently no mechanism for adding new platforms, as the setup is
+ * not automated. We could use getProperty("os.arch") perhaps, but that's
+ * debatable (could be upper/lowercase, have spaces, etc.. basically we don't
+ * know if name is proper Java package syntax.)
+ */
+public class Platform {
+ Base base;
+
+
+ /**
+ * Set the default L & F. While I enjoy the bounty of the sixteen possible
+ * exception types that this UIManager method might throw, I feel that in
+ * just this one particular case, I'm being spoiled by those engineers
+ * at Sun, those Masters of the Abstractionverse. It leaves me feeling sad
+ * and overweight. So instead, I'll pretend that I'm not offered eleven dozen
+ * ways to report to the user exactly what went wrong, and I'll bundle them
+ * all into a single catch-all "Exception". Because in the end, all I really
+ * care about is whether things worked or not. And even then, I don't care.
+ *
+ * @throws Exception Just like I said.
+ */
+ public void setLookAndFeel() throws Exception {
+ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+ }
+
+
+ public void init(Base base) {
+ this.base = base;
+ }
+
+
+ public File getSettingsFolder() throws Exception {
+ // otherwise make a .processing directory int the user's home dir
+ File home = new File(System.getProperty("user.home"));
+ File dataFolder = new File(home, ".processing");
+ return dataFolder;
+
+ /*
+ try {
+ Class clazz = Class.forName("processing.app.macosx.ThinkDifferent");
+ Method m = clazz.getMethod("getLibraryFolder", new Class[] { });
+ String libraryPath = (String) m.invoke(null, new Object[] { });
+ //String libraryPath = BaseMacOS.getLibraryFolder();
+ File libraryFolder = new File(libraryPath);
+ dataFolder = new File(libraryFolder, "Processing");
+
+ } catch (Exception e) {
+ showError("Problem getting data folder",
+ "Error getting the Processing data folder.", e);
+ }
+ */
+ }
+
+
+ /**
+ * @return null if not overridden, which will cause a prompt to show instead.
+ * @throws Exception
+ */
+ public File getDefaultSketchbookFolder() throws Exception {
+ return null;
+ }
+
+
+ public void openURL(String url) throws Exception {
+ String launcher = Preferences.get("launcher");
+ if (launcher != null) {
+ Runtime.getRuntime().exec(new String[] { launcher, url });
+ } else {
+ showLauncherWarning();
+ }
+ }
+
+
+ public boolean openFolderAvailable() {
+ return Preferences.get("launcher") != null;
+ }
+
+
+ public void openFolder(File file) throws Exception {
+ String launcher = Preferences.get("launcher");
+ if (launcher != null) {
+ String folder = file.getAbsolutePath();
+ Runtime.getRuntime().exec(new String[] { launcher, folder });
+ } else {
+ showLauncherWarning();
+ }
+ }
+
+
+ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+
+
+ protected void showLauncherWarning() {
+ Base.showWarning("No launcher available",
+ "Unspecified platform, no launcher available.\n" +
+ "To enable opening URLs or folders, add a \n" +
+ "\"launcher=/path/to/app\" line to preferences.txt",
+ null);
+ }
+}
\ No newline at end of file
diff --git a/app/src/processing/app/Preferences.java b/app/src/processing/app/Preferences.java
new file mode 100644
index 000000000..c6b53d0da
--- /dev/null
+++ b/app/src/processing/app/Preferences.java
@@ -0,0 +1,909 @@
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+/*
+ Part of the Processing project - http://processing.org
+
+ Copyright (c) 2004-06 Ben Fry and Casey Reas
+ Copyright (c) 2001-04 Massachusetts Institute of Technology
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+package processing.app;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.util.*;
+
+import javax.swing.*;
+
+import processing.app.syntax.*;
+import processing.core.*;
+
+
+
+
+/**
+ * Storage class for user preferences and environment settings.
+ *
+ * This class no longer uses the Properties class, since
+ * properties files are iso8859-1, which is highly likely to
+ * be a problem when trying to save sketch folders and locations.
+ *
+ * The GUI portion in here is really ugly, as it uses exact layout. This was
+ * done in frustration one evening (and pre-Swing), but that's long since past,
+ * and it should all be moved to a proper swing layout like BoxLayout.
+ *
+ * This is very poorly put together, that the preferences panel and the actual
+ * preferences i/o is part of the same code. But there hasn't yet been a
+ * compelling reason to bother with the separation aside from concern about
+ * being lectured by strangers who feel that it doesn't look like what they
+ * learned in CS class.
+ *
+ * Would also be possible to change this to use the Java Preferences API.
+ * Some useful articles
+ * here and
+ * here.
+ * However, haven't implemented this yet for lack of time, but more
+ * importantly, because it would entail writing to the registry (on Windows),
+ * or an obscure file location (on Mac OS X) and make it far more difficult to
+ * find the preferences to tweak them by hand (no! stay out of regedit!)
+ * or to reset the preferences by simply deleting the preferences.txt file.
+ */
+public class Preferences {
+
+ // what to call the feller
+
+ static final String PREFS_FILE = "preferences.txt";
+
+
+ // platform strings (used to get settings for specific platforms)
+
+ //static final String platforms[] = {
+ // "other", "windows", "macosx", "linux"
+ //};
+
+
+ // prompt text stuff
+
+ static final String PROMPT_YES = "Yes";
+ static final String PROMPT_NO = "No";
+ static final String PROMPT_CANCEL = "Cancel";
+ static final String PROMPT_OK = "OK";
+ static final String PROMPT_BROWSE = "Browse";
+
+ /**
+ * Standardized width for buttons. Mac OS X 10.3 wants 70 as its default,
+ * Windows XP needs 66, and my Ubuntu machine needs 80+, so 80 seems proper.
+ */
+ static public int BUTTON_WIDTH = 80;
+
+ /**
+ * Standardized button height. Mac OS X 10.3 (Java 1.4) wants 29,
+ * presumably because it now includes the blue border, where it didn't
+ * in Java 1.3. Windows XP only wants 23 (not sure what default Linux
+ * would be). Because of the disparity, on Mac OS X, it will be set
+ * inside a static block.
+ */
+ static public int BUTTON_HEIGHT = 24;
+ /*
+ // remove this for 0121, because quaqua takes care of it
+ static {
+ if (Base.isMacOS()) BUTTON_HEIGHT = 29;
+ }
+ */
+
+ // value for the size bars, buttons, etc
+
+ static final int GRID_SIZE = 33;
+
+
+ // indents and spacing standards. these probably need to be modified
+ // per platform as well, since macosx is so huge, windows is smaller,
+ // and linux is all over the map
+
+ static final int GUI_BIG = 13;
+ static final int GUI_BETWEEN = 10;
+ static final int GUI_SMALL = 6;
+
+ // gui elements
+
+ JFrame dialog;
+ int wide, high;
+
+ JTextField sketchbookLocationField;
+ JCheckBox exportSeparateBox;
+ JCheckBox deletePreviousBox;
+// JCheckBox closingLastQuitsBox;
+ JCheckBox externalEditorBox;
+ JCheckBox memoryOverrideBox;
+ JTextField memoryField;
+ JCheckBox checkUpdatesBox;
+ JTextField fontSizeField;
+ JCheckBox autoAssociateBox;
+ JCheckBox menubarWorkaroundBox;
+
+
+ // the calling editor, so updates can be applied
+
+ Editor editor;
+
+
+ // data model
+
+ static Hashtable defaults;
+ static Hashtable table = new Hashtable();;
+ static File preferencesFile;
+
+
+ static protected void init(String commandLinePrefs) {
+
+ // start by loading the defaults, in case something
+ // important was deleted from the user prefs
+ try {
+ load(Base.getLibStream("preferences.txt"));
+ } catch (Exception e) {
+ Base.showError(null, "Could not read default settings.\n" +
+ "You'll need to reinstall Processing.", e);
+ }
+
+ // check for platform-specific properties in the defaults
+ String platformExt = "." + PConstants.platformNames[PApplet.platform];
+ 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);
+ }
+ }
+
+ // clone the hash table
+ defaults = (Hashtable) table.clone();
+
+ // other things that have to be set explicitly for the defaults
+ setColor("run.window.bgcolor", SystemColor.control);
+
+ // 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
+
+ try {
+ load(new FileInputStream(preferencesFile));
+
+ } catch (Exception ex) {
+ Base.showError("Error reading preferences",
+ "Error reading the preferences file. " +
+ "Please delete (or move)\n" +
+ preferencesFile.getAbsolutePath() +
+ " and restart Processing.", ex);
+ }
+ }
+
+ // Theme settings always override preferences
+// try {
+// load(Base.getStream("theme/theme.txt"));
+// } catch (Exception te) {
+// Base.showError(null, "Could not read color theme settings.\n" +
+// "You'll need to reinstall Processing.", te);
+// }
+ }
+ }
+
+
+ public Preferences() {
+
+ // setup dialog for the prefs
+
+ //dialog = new JDialog(editor, "Preferences", true);
+ dialog = new JFrame("Preferences");
+ dialog.setResizable(false);
+
+ Container pain = dialog.getContentPane();
+ pain.setLayout(null);
+
+ int top = GUI_BIG;
+ int left = GUI_BIG;
+ int right = 0;
+
+ JLabel label;
+ JButton button; //, button2;
+ //JComboBox combo;
+ Dimension d, d2; //, d3;
+ int h, vmax;
+
+
+ // [ ] Quit after closing last sketch window
+ /*
+ closingLastQuitsBox =
+ new JCheckBox("Quit after closing last sketch window");
+ pain.add(closingLastQuitsBox);
+ d = closingLastQuitsBox.getPreferredSize();
+ closingLastQuitsBox.setBounds(left, top, d.width + 10, d.height);
+ right = Math.max(right, left + d.width);
+ top += d.height + GUI_BETWEEN;
+ */
+
+
+ /*
+ // [ ] Prompt for name and folder when creating new sketch
+
+ sketchPromptBox =
+ new JCheckBox("Prompt for name when opening or creating a sketch");
+ pain.add(sketchPromptBox);
+ d = sketchPromptBox.getPreferredSize();
+ sketchPromptBox.setBounds(left, top, d.width + 10, d.height);
+ right = Math.max(right, left + d.width);
+ top += d.height + GUI_BETWEEN;
+ */
+
+
+ // [ ] Delete empty sketches on Quit
+
+ /*
+ sketchCleanBox = new JCheckBox("Delete empty sketches on Quit");
+ pain.add(sketchCleanBox);
+ d = sketchCleanBox.getPreferredSize();
+ sketchCleanBox.setBounds(left, top, d.width + 10, d.height);
+ right = Math.max(right, left + d.width);
+ top += d.height + GUI_BETWEEN;
+ */
+
+
+ // Sketchbook location:
+ // [...............................] [ Browse ]
+
+ label = new JLabel("Sketchbook location:");
+ pain.add(label);
+ d = label.getPreferredSize();
+ label.setBounds(left, top, d.width, d.height);
+ top += d.height; // + GUI_SMALL;
+
+ sketchbookLocationField = new JTextField(40);
+ pain.add(sketchbookLocationField);
+ d = sketchbookLocationField.getPreferredSize();
+
+ button = new JButton(PROMPT_BROWSE);
+ button.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ /*
+ JFileChooser fc = new JFileChooser();
+ fc.setSelectedFile(new File(sketchbookLocationField.getText()));
+ fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
+
+ int returned = fc.showOpenDialog(new JDialog());
+ if (returned == JFileChooser.APPROVE_OPTION) {
+ File file = fc.getSelectedFile();
+ sketchbookLocationField.setText(file.getAbsolutePath());
+ }
+ */
+ File dflt = new File(sketchbookLocationField.getText());
+ File file =
+ Base.selectFolder("Select new sketchbook location", dflt, dialog);
+ if (file != null) {
+ sketchbookLocationField.setText(file.getAbsolutePath());
+ }
+ }
+ });
+ pain.add(button);
+ d2 = button.getPreferredSize();
+
+ // take max height of all components to vertically align em
+ vmax = Math.max(d.height, d2.height);
+ //label.setBounds(left, top + (vmax-d.height)/2,
+ // d.width, d.height);
+
+ //h = left + d.width + GUI_BETWEEN;
+ sketchbookLocationField.setBounds(left, top + (vmax-d.height)/2,
+ d.width, d.height);
+ h = left + d.width + GUI_SMALL; //GUI_BETWEEN;
+ button.setBounds(h, top + (vmax-d2.height)/2,
+ d2.width, d2.height);
+
+ right = Math.max(right, h + d2.width + GUI_BIG);
+ top += vmax + GUI_BETWEEN;
+
+
+ // Editor font size [ ]
+
+ Container box = Box.createHorizontalBox();
+ label = new JLabel("Editor font size: ");
+ box.add(label);
+ fontSizeField = new JTextField(4);
+ box.add(fontSizeField);
+ label = new JLabel(" (requires restart of Processing)");
+ box.add(label);
+ 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()));
+ top += d.height + GUI_BETWEEN;
+
+
+ // [ ] Increase maximum available memory to [______] MB
+
+ Container memoryBox = Box.createHorizontalBox();
+ memoryOverrideBox = new JCheckBox("Increase maximum available memory to ");
+ memoryBox.add(memoryOverrideBox);
+ memoryField = new JTextField(4);
+ memoryBox.add(memoryField);
+ memoryBox.add(new JLabel(" MB"));
+ pain.add(memoryBox);
+ d = memoryBox.getPreferredSize();
+ memoryBox.setBounds(left, top, d.width, d.height);
+ 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 applet or application folder on export
+
+ deletePreviousBox =
+ new JCheckBox("Delete previous applet or application folder on export");
+ pain.add(deletePreviousBox);
+ d = deletePreviousBox.getPreferredSize();
+ deletePreviousBox.setBounds(left, top, d.width + 10, d.height);
+ right = Math.max(right, left + d.width);
+ 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;
+
+
+ // [ ] Check for updates on startup
+
+ checkUpdatesBox = new JCheckBox("Check for updates on startup");
+ pain.add(checkUpdatesBox);
+ d = checkUpdatesBox.getPreferredSize();
+ checkUpdatesBox.setBounds(left, top, d.width + 10, d.height);
+ right = Math.max(right, left + d.width);
+ top += d.height + GUI_BETWEEN;
+
+
+ // [ ] Automatically associate .pde files with Processing
+
+ if (Base.isWindows()) {
+ autoAssociateBox =
+ new JCheckBox("Automatically associate .pde files with Processing");
+ pain.add(autoAssociateBox);
+ d = autoAssociateBox.getPreferredSize();
+ autoAssociateBox.setBounds(left, top, d.width + 10, d.height);
+ right = Math.max(right, left + d.width);
+ top += d.height + GUI_BETWEEN;
+ }
+
+
+ // [ ] Place menu bar inside
+
+ if (Base.isMacOS()) {
+ if (System.getProperty("os.version").startsWith("10.5")) {
+ menubarWorkaroundBox =
+ new JCheckBox("Place menus inside editor window to avoid " +
+ "Apple Java bug (requires restart)");
+ pain.add(menubarWorkaroundBox);
+ d = menubarWorkaroundBox.getPreferredSize();
+ menubarWorkaroundBox.setBounds(left, top, d.width + 10, d.height);
+ right = Math.max(right, left + d.width);
+ top += d.height + GUI_BETWEEN;
+ }
+ }
+
+
+ // More preferences are in the ...
+
+ label = new JLabel("More preferences can be edited directly in the file");
+ pain.add(label);
+ d = label.getPreferredSize();
+ label.setForeground(Color.gray);
+ label.setBounds(left, top, d.width, d.height);
+ right = Math.max(right, left + d.width);
+ top += d.height; // + GUI_SMALL;
+
+ label = new JLabel(preferencesFile.getAbsolutePath());
+ pain.add(label);
+ d = label.getPreferredSize();
+ label.setBounds(left, top, d.width, d.height);
+ right = Math.max(right, left + d.width);
+ top += d.height;
+
+ label = new JLabel("(edit only when Processing is not running)");
+ pain.add(label);
+ d = label.getPreferredSize();
+ label.setForeground(Color.gray);
+ label.setBounds(left, top, d.width, d.height);
+ right = Math.max(right, left + d.width);
+ top += d.height; // + GUI_SMALL;
+
+
+ // [ OK ] [ Cancel ] maybe these should be next to the message?
+
+ button = new JButton(PROMPT_OK);
+ button.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ applyFrame();
+ disposeFrame();
+ }
+ });
+ pain.add(button);
+ d2 = button.getPreferredSize();
+ BUTTON_HEIGHT = d2.height;
+
+ h = right - (BUTTON_WIDTH + GUI_SMALL + BUTTON_WIDTH);
+ button.setBounds(h, top, BUTTON_WIDTH, BUTTON_HEIGHT);
+ h += BUTTON_WIDTH + GUI_SMALL;
+
+ button = new JButton(PROMPT_CANCEL);
+ button.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ disposeFrame();
+ }
+ });
+ pain.add(button);
+ button.setBounds(h, top, BUTTON_WIDTH, BUTTON_HEIGHT);
+
+ top += BUTTON_HEIGHT + GUI_BETWEEN;
+
+
+ // finish up
+
+ wide = right + GUI_BIG;
+ high = top + GUI_SMALL;
+ //setSize(wide, high);
+
+
+ // closing the window is same as hitting cancel button
+
+ dialog.addWindowListener(new WindowAdapter() {
+ public void windowClosing(WindowEvent e) {
+ disposeFrame();
+ }
+ });
+
+ ActionListener disposer = new ActionListener() {
+ public void actionPerformed(ActionEvent actionEvent) {
+ disposeFrame();
+ }
+ };
+ Base.registerWindowCloseKeys(dialog.getRootPane(), disposer);
+ Base.setIcon(dialog);
+
+ Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
+ dialog.setLocation((screen.width - wide) / 2,
+ (screen.height - high) / 2);
+
+ dialog.pack(); // get insets
+ Insets insets = dialog.getInsets();
+ dialog.setSize(wide + insets.left + insets.right,
+ high + insets.top + insets.bottom);
+
+
+ // handle window closing commands for ctrl/cmd-W or hitting ESC.
+
+ pain.addKeyListener(new KeyAdapter() {
+ public void keyPressed(KeyEvent e) {
+ //System.out.println(e);
+ KeyStroke wc = Editor.WINDOW_CLOSE_KEYSTROKE;
+ if ((e.getKeyCode() == KeyEvent.VK_ESCAPE) ||
+ (KeyStroke.getKeyStrokeForEvent(e).equals(wc))) {
+ disposeFrame();
+ }
+ }
+ });
+ }
+
+
+ /*
+ protected JRootPane createRootPane() {
+ System.out.println("creating root pane esc received");
+
+ ActionListener actionListener = new ActionListener() {
+ public void actionPerformed(ActionEvent actionEvent) {
+ //setVisible(false);
+ System.out.println("esc received");
+ }
+ };
+
+ JRootPane rootPane = new JRootPane();
+ KeyStroke stroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
+ rootPane.registerKeyboardAction(actionListener, stroke,
+ JComponent.WHEN_IN_FOCUSED_WINDOW);
+ return rootPane;
+ }
+ */
+
+
+ public Dimension getPreferredSize() {
+ return new Dimension(wide, high);
+ }
+
+
+ // .................................................................
+
+
+ /**
+ * Close the window after an OK or Cancel.
+ */
+ protected void disposeFrame() {
+ dialog.dispose();
+ }
+
+
+ /**
+ * Change internal settings based on what was chosen in the prefs,
+ * then send a message to the editor saying that it's time to do the same.
+ */
+ protected void applyFrame() {
+ // put each of the settings into the table
+ setBoolean("export.applet.separate_jar_files",
+ exportSeparateBox.isSelected());
+ setBoolean("export.delete_target_folder",
+ deletePreviousBox.isSelected());
+
+// setBoolean("sketchbook.closing_last_window_quits",
+// closingLastQuitsBox.isSelected());
+ //setBoolean("sketchbook.prompt", sketchPromptBox.isSelected());
+ //setBoolean("sketchbook.auto_clean", sketchCleanBox.isSelected());
+
+ // if the sketchbook path has changed, rebuild the menus
+ String oldPath = get("sketchbook.path");
+ String newPath = sketchbookLocationField.getText();
+ if (!newPath.equals(oldPath)) {
+ editor.base.rebuildSketchbookMenus();
+ set("sketchbook.path", newPath);
+ }
+
+ setBoolean("editor.external", externalEditorBox.isSelected());
+ setBoolean("update.check", checkUpdatesBox.isSelected());
+
+ setBoolean("run.options.memory", memoryOverrideBox.isSelected());
+ int memoryMin = Preferences.getInteger("run.options.memory.initial");
+ int memoryMax = Preferences.getInteger("run.options.memory.maximum");
+ try {
+ memoryMax = Integer.parseInt(memoryField.getText().trim());
+ // make sure memory setting isn't too small
+ if (memoryMax < memoryMin) memoryMax = memoryMin;
+ setInteger("run.options.memory.maximum", memoryMax);
+ } catch (NumberFormatException e) {
+ 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);
+ }
+ */
+
+ String newSizeText = fontSizeField.getText();
+ try {
+ int newSize = Integer.parseInt(newSizeText.trim());
+ String pieces[] = PApplet.split(get("editor.font"), ',');
+ pieces[2] = String.valueOf(newSize);
+ set("editor.font", PApplet.join(pieces, ','));
+
+ } catch (Exception e) {
+ System.err.println("ignoring invalid font size " + newSizeText);
+ }
+
+ if (autoAssociateBox != null) {
+ setBoolean("platform.auto_file_type_associations",
+ autoAssociateBox.isSelected());
+ }
+
+ if (menubarWorkaroundBox != null) {
+ setBoolean("apple.laf.useScreenMenuBar",
+ !menubarWorkaroundBox.isSelected());
+ }
+
+ editor.applyPreferences();
+ }
+
+
+ protected void showFrame(Editor editor) {
+ this.editor = editor;
+
+ // set all settings entry boxes to their actual status
+ exportSeparateBox.
+ setSelected(getBoolean("export.applet.separate_jar_files"));
+ deletePreviousBox.
+ setSelected(getBoolean("export.delete_target_folder"));
+
+ //closingLastQuitsBox.
+ // setSelected(getBoolean("sketchbook.closing_last_window_quits"));
+ //sketchPromptBox.
+ // setSelected(getBoolean("sketchbook.prompt"));
+ //sketchCleanBox.
+ // setSelected(getBoolean("sketchbook.auto_clean"));
+
+ sketchbookLocationField.
+ setText(get("sketchbook.path"));
+ externalEditorBox.
+ setSelected(getBoolean("editor.external"));
+ checkUpdatesBox.
+ setSelected(getBoolean("update.check"));
+ memoryOverrideBox.
+ setSelected(getBoolean("run.options.memory"));
+ memoryField.
+ setText(get("run.options.memory.maximum"));
+
+ if (autoAssociateBox != null) {
+ autoAssociateBox.
+ setSelected(getBoolean("platform.auto_file_type_associations"));
+ }
+
+ if (menubarWorkaroundBox != null) {
+ menubarWorkaroundBox.
+ setSelected(!getBoolean("apple.laf.useScreenMenuBar"));
+ }
+
+ dialog.setVisible(true);
+ }
+
+
+ // .................................................................
+
+
+ static protected void load(InputStream input) throws IOException {
+ String[] lines = PApplet.loadStrings(input); // Reads as UTF-8
+ for (String line : lines) {
+ if ((line.length() == 0) ||
+ (line.charAt(0) == '#')) continue;
+
+ // this won't properly handle = signs being in the text
+ int equals = line.indexOf('=');
+ if (equals != -1) {
+ String key = line.substring(0, equals).trim();
+ String value = line.substring(equals + 1).trim();
+ table.put(key, value);
+ }
+ }
+ }
+
+
+ // .................................................................
+
+
+ static protected void save() {
+// try {
+ // on startup, don't worry about it
+ // this is trying to update the prefs for who is open
+ // before Preferences.init() has been called.
+ if (preferencesFile == null) return;
+
+ // Fix for 0163 to properly use Unicode when writing preferences.txt
+ PrintWriter writer = PApplet.createWriter(preferencesFile);
+
+ Enumeration e = table.keys(); //properties.propertyNames();
+ while (e.hasMoreElements()) {
+ String key = (String) e.nextElement();
+ writer.println(key + "=" + ((String) table.get(key)));
+ }
+
+ writer.flush();
+ writer.close();
+
+// } catch (Exception ex) {
+// Base.showWarning(null, "Error while saving the settings file", ex);
+// }
+ }
+
+
+ // .................................................................
+
+
+ // 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 (String) table.get(attribute);
+ /*
+ //String value = (properties != null) ?
+ //properties.getProperty(attribute) : applet.getParameter(attribute);
+ String value = properties.getProperty(attribute);
+
+ return (value == null) ?
+ defaultValue : value;
+ */
+ }
+
+
+ static public String getDefault(String attribute) {
+ return (String) defaults.get(attribute);
+ }
+
+
+ static public void set(String attribute, String value) {
+ table.put(attribute, value);
+ }
+
+
+ static public boolean getBoolean(String attribute) {
+ String value = get(attribute); //, null);
+ return (new Boolean(value)).booleanValue();
+
+ /*
+ supposedly not needed, because anything besides 'true'
+ (ignoring case) will just be false.. so if malformed -> false
+ if (value == null) return defaultValue;
+
+ try {
+ return (new Boolean(value)).booleanValue();
+ } catch (NumberFormatException e) {
+ System.err.println("expecting an integer: " + attribute + " = " + value);
+ }
+ return defaultValue;
+ */
+ }
+
+
+ static public void setBoolean(String attribute, boolean value) {
+ set(attribute, value ? "true" : "false");
+ }
+
+
+ static public int getInteger(String attribute /*, int defaultValue*/) {
+ return Integer.parseInt(get(attribute));
+
+ /*
+ String value = get(attribute, null);
+ if (value == null) return defaultValue;
+
+ try {
+ return Integer.parseInt(value);
+ } catch (NumberFormatException e) {
+ // ignored will just fall through to returning the default
+ System.err.println("expecting an integer: " + attribute + " = " + value);
+ }
+ return defaultValue;
+ //if (value == null) return defaultValue;
+ //return (value == null) ? defaultValue :
+ //Integer.parseInt(value);
+ */
+ }
+
+
+ static public void setInteger(String key, int value) {
+ set(key, String.valueOf(value));
+ }
+
+
+ static public Color getColor(String name) {
+ Color parsed = Color.GRAY; // set a default
+ String s = get(name);
+ if ((s != null) && (s.indexOf("#") == 0)) {
+ try {
+ parsed = new Color(Integer.parseInt(s.substring(1), 16));
+ } catch (Exception e) { }
+ }
+ return parsed;
+ }
+
+
+ static public void setColor(String attr, Color what) {
+// String r = Integer.toHexString(what.getRed());
+// String g = Integer.toHexString(what.getGreen());
+// String b = Integer.toHexString(what.getBlue());
+// set(attr, "#" + r.substring(r.length() - 2) +
+// g.substring(g.length() - 2) + b.substring(b.length() - 2));
+ set(attr, "#" + PApplet.hex(what.getRGB() & 0xffffff, 6));
+ }
+
+
+ static public Font getFont(String attr) {
+ boolean replace = false;
+ String value = get(attr);
+ if (value == null) {
+ //System.out.println("reset 1");
+ value = getDefault(attr);
+ replace = true;
+ }
+
+ String[] pieces = PApplet.split(value, ',');
+ if (pieces.length != 3) {
+ value = getDefault(attr);
+ //System.out.println("reset 2 for " + attr);
+ pieces = PApplet.split(value, ',');
+ //PApplet.println(pieces);
+ replace = true;
+ }
+
+ String name = pieces[0];
+ int style = Font.PLAIN; // equals zero
+ if (pieces[1].indexOf("bold") != -1) {
+ style |= Font.BOLD;
+ }
+ if (pieces[1].indexOf("italic") != -1) {
+ style |= Font.ITALIC;
+ }
+ int size = PApplet.parseInt(pieces[2], 12);
+ Font font = new Font(name, style, size);
+
+ // replace bad font with the default
+ if (replace) {
+ set(attr, value);
+ }
+
+ return font;
+ }
+
+
+ static public SyntaxStyle getStyle(String what /*, String dflt*/) {
+ String str = get("editor." + what + ".style"); //, dflt);
+
+ StringTokenizer st = new StringTokenizer(str, ",");
+
+ String s = st.nextToken();
+ if (s.indexOf("#") == 0) s = s.substring(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);
+ boolean italic = (s.indexOf("italic") != -1);
+ //System.out.println(what + " = " + str + " " + bold + " " + italic);
+
+ return new SyntaxStyle(color, italic, bold);
+ }
+}
diff --git a/app/src/processing/app/PresentMode.java b/app/src/processing/app/PresentMode.java
new file mode 100644
index 000000000..63f4578d9
--- /dev/null
+++ b/app/src/processing/app/PresentMode.java
@@ -0,0 +1,128 @@
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+/*
+ Part of the Processing project - http://processing.org
+
+ Copyright (c) 2005-06 Ben Fry and Casey Reas
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+package processing.app;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.Vector;
+import javax.swing.*;
+
+
+/**
+ * Helper class for full-screen presentation mode.
+ */
+public class PresentMode {
+
+ static GraphicsDevice devices[];
+
+ /**
+ * Index of the default display device, probably the one that p5 was
+ * started from.
+ */
+ static int defaultIndex;
+
+ /**
+ * Menu object for preferences window
+ */
+ //JMenu preferencesMenu;
+ static JComboBox selector;
+
+ /**
+ * Index of the currently selected display to be used for present mode.
+ */
+ static GraphicsDevice device;
+
+
+ static {
+ GraphicsEnvironment environment =
+ GraphicsEnvironment.getLocalGraphicsEnvironment();
+ devices = environment.getScreenDevices();
+ GraphicsDevice defaultDevice = environment.getDefaultScreenDevice();
+
+ Vector names = new Vector();
+ for (int i = 0; i < devices.length; i++) {
+ String name = String.valueOf(i + 1);
+ if (devices[i] == defaultDevice) {
+ defaultIndex = i;
+ name += " (default)";
+ }
+ names.add(name);
+ }
+
+ selector = new JComboBox(names);
+ selector.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ int index = selector.getSelectedIndex();
+ //device = devices[index];
+ Preferences.setInteger("run.present.display", index + 1);
+ }
+ });
+ }
+
+
+ static public JComboBox getSelector() {
+ int deviceIndex = Preferences.getInteger("run.present.display") - 1;
+ selector.setSelectedIndex(deviceIndex);
+ return selector;
+ }
+
+
+ /*
+ static public JFrame create() {
+ int deviceIndex = PrePreferences.getInteger("run.present.display") - 1;
+ if ((deviceIndex < 0) || (deviceIndex >= devices.length)) {
+ Base.showWarning("Display doesn't exist",
+ "Present Mode is set to use display " +
+ (deviceIndex+1) +
+ " but that doesn't seem to exist. \n" +
+ "This preference will be reset to " +
+ "use the default display.", null);
+ deviceIndex = defaultIndex;
+ }
+ //GraphicsDevice device = devices[
+ //JFrame frame = new JFrame(devices[deviceIndex]);
+ PresentFrame frame = new PresentFrame(devices[deviceIndex]);
+ }
+
+
+ public void show() {
+ setUndecorated(true);
+ setResizable(false);
+ device.setFullScreenWindow(this);
+ }
+
+
+ public Window getWindow() {
+ return device.getFullScreenWindow(); // isn't this just me?
+ }
+
+
+ public void dispose() {
+ Window window = device.getFullScreenWindow();
+ if (window != null) {
+ window.dispose();
+ }
+ device.setFullScreenWindow(null);
+ }
+ */
+}
diff --git a/app/src/processing/app/Sketch.java b/app/src/processing/app/Sketch.java
new file mode 100644
index 000000000..28f253b8c
--- /dev/null
+++ b/app/src/processing/app/Sketch.java
@@ -0,0 +1,3004 @@
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+/*
+ Part of the Processing project - http://processing.org
+
+ Copyright (c) 2004-08 Ben Fry and Casey Reas
+ Copyright (c) 2001-04 Massachusetts Institute of Technology
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+package processing.app;
+
+import processing.app.debug.Compiler;
+import processing.app.debug.RunnerException;
+import processing.app.preproc.*;
+import processing.core.*;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.beans.*;
+import java.io.*;
+import java.util.*;
+import java.util.zip.*;
+
+import javax.swing.*;
+import javax.swing.border.EmptyBorder;
+import javax.swing.border.TitledBorder;
+
+
+/**
+ * Stores information about files in the current sketch
+ */
+public class Sketch {
+ static private File tempBuildFolder;
+
+ private Editor editor;
+
+ /** main pde file for this sketch. */
+ private File primaryFile;
+
+ /**
+ * Name of sketch, which is the name of main file
+ * (without .pde or .java extension)
+ */
+ private String name;
+
+ /** true if any of the files have been modified. */
+ private boolean modified;
+
+ /** folder that contains this sketch */
+ private File folder;
+
+ /** data folder location for this sketch (may not exist yet) */
+ private File dataFolder;
+
+ /** code folder location for this sketch (may not exist yet) */
+ private File codeFolder;
+
+ private SketchCode current;
+ private int currentIndex;
+ /**
+ * Number of sketchCode objects (tabs) in the current sketch. Note that this
+ * will be the same as code.length, because the getCode() method returns
+ * just the code[] array, rather than a copy of it, or an array that's been
+ * resized to just the relevant files themselves.
+ * http://dev.processing.org/bugs/show_bug.cgi?id=940
+ */
+ private int codeCount;
+ private SketchCode[] code;
+
+ /** Class name for the PApplet, as determined by the preprocessor. */
+ private String appletClassName;
+ /** Class path determined during build. */
+ private String classPath;
+
+ /**
+ * This is *not* the "Processing" libraries path, this is the Java libraries
+ * path, as in java.library.path=BlahBlah, which identifies search paths for
+ * DLLs or JNILIBs.
+ */
+ private String libraryPath;
+ private ArrayList importedLibraries;
+
+ /**
+ * path is location of the main .pde file, because this is also
+ * simplest to use when opening the file from the finder/explorer.
+ */
+ public Sketch(Editor editor, String path) throws IOException {
+ this.editor = editor;
+
+ primaryFile = new File(path);
+
+ // get the name of the sketch by chopping .pde or .java
+ // off of the main file name
+ String mainFilename = primaryFile.getName();
+ int suffixLength = getDefaultExtension().length() + 1;
+ name = mainFilename.substring(0, mainFilename.length() - suffixLength);
+
+ // lib/build must exist when the application is started
+ // it is added to the CLASSPATH by default, but if it doesn't
+ // exist when the application is started, then java will remove
+ // the entry from the CLASSPATH, causing Runner to fail.
+ //
+ /*
+ tempBuildFolder = new File(TEMP_BUILD_PATH);
+ if (!tempBuildFolder.exists()) {
+ tempBuildFolder.mkdirs();
+ Base.showError("Required folder missing",
+ "A required folder was missing from \n" +
+ "from your installation of Processing.\n" +
+ "It has now been replaced, please restart \n" +
+ "the application to complete the repair.", null);
+ }
+ */
+ tempBuildFolder = Base.getBuildFolder();
+ //Base.addBuildFolderToClassPath();
+
+ folder = new File(new File(path).getParent());
+ //System.out.println("sketch dir is " + folder);
+
+ load();
+ }
+
+
+ /**
+ * Build the list of files.
+ *
+ * Generally this is only done once, rather than
+ * each time a change is made, because otherwise it gets to be
+ * a nightmare to keep track of what files went where, because
+ * not all the data will be saved to disk.
+ *
+ * This also gets called when the main sketch file is renamed,
+ * because the sketch has to be reloaded from a different folder.
+ *
+ * Another exception is when an external editor is in use,
+ * in which case the load happens each time "run" is hit.
+ */
+ protected void load() {
+ codeFolder = new File(folder, "code");
+ dataFolder = new File(folder, "data");
+
+ // get list of files in the sketch folder
+ String list[] = folder.list();
+
+ // reset these because load() may be called after an
+ // external editor event. (fix for 0099)
+ codeCount = 0;
+
+ code = new SketchCode[list.length];
+
+ String[] extensions = getExtensions();
+
+ for (String filename : list) {
+ // Ignoring the dot prefix files is especially important to avoid files
+ // with the ._ prefix on Mac OS X. (You'll see this with Mac files on
+ // non-HFS drives, i.e. a thumb drive formatted FAT32.)
+ if (filename.startsWith(".")) continue;
+
+ // Don't let some wacko name a directory blah.pde or bling.java.
+ if (new File(folder, filename).isDirectory()) continue;
+
+ // figure out the name without any extension
+ String base = filename;
+ // now strip off the .pde and .java extensions
+ for (String extension : extensions) {
+ if (base.toLowerCase().endsWith("." + extension)) {
+ base = base.substring(0, base.length() - (extension.length() + 1));
+
+ // Don't allow people to use files with invalid names, since on load,
+ // it would be otherwise possible to sneak in nasty filenames. [0116]
+ if (Sketch.isSanitaryName(base)) {
+ code[codeCount++] =
+ new SketchCode(new File(folder, filename), extension);
+ }
+ }
+ }
+ }
+ // Remove any code that wasn't proper
+ code = (SketchCode[]) PApplet.subset(code, 0, codeCount);
+
+ // move the main class to the first tab
+ // start at 1, if it's at zero, don't bother
+ for (int i = 1; i < codeCount; i++) {
+ //if (code[i].file.getName().equals(mainFilename)) {
+ if (code[i].getFile().equals(primaryFile)) {
+ SketchCode temp = code[0];
+ code[0] = code[i];
+ code[i] = temp;
+ break;
+ }
+ }
+
+ // sort the entries at the top
+ sortCode();
+
+ // set the main file to be the current tab
+ if (editor != null) {
+ setCurrentCode(0);
+ }
+ }
+
+
+ protected void replaceCode(SketchCode newCode) {
+ for (int i = 0; i < codeCount; i++) {
+ if (code[i].getFileName().equals(newCode.getFileName())) {
+ code[i] = newCode;
+ break;
+ }
+ }
+ }
+
+
+ protected void insertCode(SketchCode newCode) {
+ // make sure the user didn't hide the sketch folder
+ ensureExistence();
+
+ // add file to the code/codeCount list, resort the list
+ if (codeCount == code.length) {
+ code = (SketchCode[]) PApplet.append(code, newCode);
+ }
+ code[codeCount++] = newCode;
+ }
+
+
+ protected void sortCode() {
+ // cheap-ass sort of the rest of the files
+ // it's a dumb, slow sort, but there shouldn't be more than ~5 files
+ for (int i = 1; i < codeCount; i++) {
+ int who = i;
+ for (int j = i + 1; j < codeCount; j++) {
+ if (code[j].getFileName().compareTo(code[who].getFileName()) < 0) {
+ who = j; // this guy is earlier in the alphabet
+ }
+ }
+ if (who != i) { // swap with someone if changes made
+ SketchCode temp = code[who];
+ code[who] = code[i];
+ code[i] = temp;
+ }
+ }
+ }
+
+
+ boolean renamingCode;
+
+ /**
+ * Handler for the New Code menu option.
+ */
+ public void handleNewCode() {
+ // make sure the user didn't hide the sketch folder
+ ensureExistence();
+
+ // if read-only, give an error
+ if (isReadOnly()) {
+ // if the files are read-only, need to first do a "save as".
+ Base.showMessage("Sketch is Read-Only",
+ "Some files are marked \"read-only\", so you'll\n" +
+ "need to re-save the sketch in another location,\n" +
+ "and try again.");
+ return;
+ }
+
+ renamingCode = false;
+ editor.status.edit("Name for new file:", "");
+ }
+
+
+ /**
+ * Handler for the Rename Code menu option.
+ */
+ public void handleRenameCode() {
+ // make sure the user didn't hide the sketch folder
+ ensureExistence();
+
+ if (currentIndex == 0 && editor.untitled) {
+ Base.showMessage("Sketch is Untitled",
+ "How about saving the sketch first \n" +
+ "before trying to rename it?");
+ return;
+ }
+
+ // if read-only, give an error
+ if (isReadOnly()) {
+ // if the files are read-only, need to first do a "save as".
+ Base.showMessage("Sketch is Read-Only",
+ "Some files are marked \"read-only\", so you'll\n" +
+ "need to re-save the sketch in another location,\n" +
+ "and try again.");
+ return;
+ }
+
+ // ask for new name of file (internal to window)
+ // TODO maybe just popup a text area?
+ renamingCode = true;
+ String prompt = (currentIndex == 0) ?
+ "New name for sketch:" : "New name for file:";
+ String oldName = (current.isExtension("pde")) ?
+ current.getPrettyName() : current.getFileName();
+ editor.status.edit(prompt, oldName);
+ }
+
+
+ /**
+ * This is called upon return from entering a new file name.
+ * (that is, from either newCode or renameCode after the prompt)
+ * This code is almost identical for both the newCode and renameCode
+ * cases, so they're kept merged except for right in the middle
+ * where they diverge.
+ */
+ protected void nameCode(String newName) {
+ // make sure the user didn't hide the sketch folder
+ ensureExistence();
+
+ // Add the extension here, this simplifies some of the logic below.
+ if (newName.indexOf('.') == -1) {
+ newName += "." + getDefaultExtension();
+ }
+
+ // if renaming to the same thing as before, just ignore.
+ // also ignoring case here, because i don't want to write
+ // a bunch of special stuff for each platform
+ // (osx is case insensitive but preserving, windows insensitive,
+ // *nix is sensitive and preserving.. argh)
+ if (renamingCode) {
+ if (newName.equalsIgnoreCase(current.getFileName())) {
+ // exit quietly for the 'rename' case.
+ // if it's a 'new' then an error will occur down below
+ return;
+ }
+ }
+
+ newName = newName.trim();
+ if (newName.equals("")) return;
+
+ int dot = newName.indexOf('.');
+ if (dot == 0) {
+ Base.showWarning("Problem with rename",
+ "The name cannot start with a period.", null);
+ return;
+ }
+
+ String newExtension = newName.substring(dot+1).toLowerCase();
+ if (!validExtension(newExtension)) {
+ Base.showWarning("Problem with rename",
+ "\"." + newExtension + "\"" +
+ "is not a valid extension.", null);
+ return;
+ }
+
+ // Don't let the user create the main tab as a .java file instead of .pde
+ if (!isDefaultExtension(newExtension)) {
+ if (renamingCode) { // If creating a new tab, don't show this error
+ if (current == code[0]) { // If this is the main tab, disallow
+ Base.showWarning("Problem with rename",
+ "The main .pde file cannot be .java file.\n" +
+ "(It may be time for your to graduate to a\n" +
+ "\"real\" programming environment)", null);
+ return;
+ }
+ }
+ }
+
+ // dots are allowed for the .pde and .java, but not in the name
+ // make sure the user didn't name things poo.time.pde
+ // or something like that (nothing against poo time)
+ String shortName = newName.substring(0, dot);
+ String sanitaryName = Sketch.sanitizeName(shortName);
+ if (!shortName.equals(sanitaryName)) {
+ newName = sanitaryName + "." + newExtension;
+ }
+
+ // Make sure no .pde *and* no .java files with the same name already exist
+ // http://dev.processing.org/bugs/show_bug.cgi?id=543
+ for (SketchCode c : code) {
+ if (sanitaryName.equals(c.getPrettyName())) {
+ Base.showMessage("Nope",
+ "A file named \"" + c.getFileName() + "\" already exists\n" +
+ "in \"" + folder.getAbsolutePath() + "\"");
+ return;
+ }
+ }
+
+ File newFile = new File(folder, newName);
+// if (newFile.exists()) { // yay! users will try anything
+// Base.showMessage("Nope",
+// "A file named \"" + newFile + "\" already exists\n" +
+// "in \"" + folder.getAbsolutePath() + "\"");
+// return;
+// }
+
+// File newFileHidden = new File(folder, newName + ".x");
+// if (newFileHidden.exists()) {
+// // don't let them get away with it if they try to create something
+// // with the same name as something hidden
+// Base.showMessage("No Way",
+// "A hidden tab with the same name already exists.\n" +
+// "Use \"Unhide\" to bring it back.");
+// return;
+// }
+
+ if (renamingCode) {
+ if (currentIndex == 0) {
+ // get the new folder name/location
+ String folderName = newName.substring(0, newName.indexOf('.'));
+ File newFolder = new File(folder.getParentFile(), folderName);
+ if (newFolder.exists()) {
+ Base.showWarning("Cannot Rename",
+ "Sorry, a sketch (or folder) named " +
+ "\"" + newName + "\" already exists.", null);
+ return;
+ }
+
+ // unfortunately this can't be a "save as" because that
+ // only copies the sketch files and the data folder
+ // however this *will* first save the sketch, then rename
+
+ // first get the contents of the editor text area
+ if (current.isModified()) {
+ current.setProgram(editor.getText());
+ try {
+ // save this new SketchCode
+ current.save();
+ } catch (Exception e) {
+ Base.showWarning("Error", "Could not rename the sketch. (0)", e);
+ return;
+ }
+ }
+
+ if (!current.renameTo(newFile, newExtension)) {
+ Base.showWarning("Error",
+ "Could not rename \"" + current.getFileName() +
+ "\" to \"" + newFile.getName() + "\"", null);
+ return;
+ }
+
+ // save each of the other tabs because this is gonna be re-opened
+ try {
+ for (int i = 1; i < codeCount; i++) {
+ code[i].save();
+ }
+ } catch (Exception e) {
+ Base.showWarning("Error", "Could not rename the sketch. (1)", e);
+ return;
+ }
+
+ // now rename the sketch folder and re-open
+ boolean success = folder.renameTo(newFolder);
+ if (!success) {
+ Base.showWarning("Error", "Could not rename the sketch. (2)", null);
+ return;
+ }
+ // if successful, set base properties for the sketch
+
+ File newMainFile = new File(newFolder, newName + ".pde");
+ String newMainFilePath = newMainFile.getAbsolutePath();
+
+ // having saved everything and renamed the folder and the main .pde,
+ // use the editor to re-open the sketch to re-init state
+ // (unfortunately this will kill positions for carets etc)
+ editor.handleOpenUnchecked(newMainFilePath,
+ currentIndex,
+ editor.getSelectionStart(),
+ editor.getSelectionStop(),
+ editor.getScrollPosition());
+
+ // get the changes into the sketchbook menu
+ // (re-enabled in 0115 to fix bug #332)
+ editor.base.rebuildSketchbookMenus();
+
+ } else { // else if something besides code[0]
+ if (!current.renameTo(newFile, newExtension)) {
+ Base.showWarning("Error",
+ "Could not rename \"" + current.getFileName() +
+ "\" to \"" + newFile.getName() + "\"", null);
+ return;
+ }
+ }
+
+ } else { // creating a new file
+ try {
+ if (!newFile.createNewFile()) {
+ // Already checking for IOException, so make our own.
+ throw new IOException("createNewFile() returned false");
+ }
+ } catch (IOException e) {
+ Base.showWarning("Error",
+ "Could not create the file \"" + newFile + "\"\n" +
+ "in \"" + folder.getAbsolutePath() + "\"", e);
+ return;
+ }
+ SketchCode newCode = new SketchCode(newFile, newExtension);
+ //System.out.println("new code is named " + newCode.getPrettyName() + " " + newCode.getFile());
+ insertCode(newCode);
+ }
+
+ // sort the entries
+ sortCode();
+
+ // set the new guy as current
+ setCurrentCode(newName);
+
+ // update the tabs
+ editor.header.rebuild();
+ }
+
+
+ /**
+ * Remove a piece of code from the sketch and from the disk.
+ */
+ public void handleDeleteCode() {
+ // make sure the user didn't hide the sketch folder
+ ensureExistence();
+
+ // if read-only, give an error
+ if (isReadOnly()) {
+ // if the files are read-only, need to first do a "save as".
+ Base.showMessage("Sketch is Read-Only",
+ "Some files are marked \"read-only\", so you'll\n" +
+ "need to re-save the sketch in another location,\n" +
+ "and try again.");
+ return;
+ }
+
+ // confirm deletion with user, yes/no
+ Object[] options = { "OK", "Cancel" };
+ String prompt = (currentIndex == 0) ?
+ "Are you sure you want to delete this sketch?" :
+ "Are you sure you want to delete \"" + current.getPrettyName() + "\"?";
+ int result = JOptionPane.showOptionDialog(editor,
+ prompt,
+ "Delete",
+ JOptionPane.YES_NO_OPTION,
+ JOptionPane.QUESTION_MESSAGE,
+ null,
+ options,
+ options[0]);
+ if (result == JOptionPane.YES_OPTION) {
+ if (currentIndex == 0) {
+ // need to unset all the modified flags, otherwise tries
+ // to do a save on the handleNew()
+
+ // delete the entire sketch
+ Base.removeDir(folder);
+
+ // get the changes into the sketchbook menu
+ //sketchbook.rebuildMenus();
+
+ // make a new sketch, and i think this will rebuild the sketch menu
+ //editor.handleNewUnchecked();
+ //editor.handleClose2();
+ editor.base.handleClose(editor);
+
+ } else {
+ // delete the file
+ if (!current.deleteFile()) {
+ Base.showMessage("Couldn't do it",
+ "Could not delete \"" +
+ current.getFileName() + "\".");
+ return;
+ }
+
+ // remove code from the list
+ removeCode(current);
+
+ // just set current tab to the main tab
+ setCurrentCode(0);
+
+ // update the tabs
+ editor.header.repaint();
+ }
+ }
+ }
+
+
+ protected void removeCode(SketchCode which) {
+ // remove it from the internal list of files
+ // resort internal list of files
+ for (int i = 0; i < codeCount; i++) {
+ if (code[i] == which) {
+ for (int j = i; j < codeCount-1; j++) {
+ code[j] = code[j+1];
+ }
+ codeCount--;
+ return;
+ }
+ }
+ System.err.println("removeCode: internal error.. could not find code");
+ }
+
+
+ /**
+ * Move to the previous tab.
+ */
+ public void handlePrevCode() {
+ int prev = currentIndex - 1;
+ if (prev < 0) prev = codeCount-1;
+ setCurrentCode(prev);
+ }
+
+
+ /**
+ * Move to the next tab.
+ */
+ public void handleNextCode() {
+ setCurrentCode((currentIndex + 1) % codeCount);
+ }
+
+
+ /**
+ * Sets the modified value for the code in the frontmost tab.
+ */
+ public void setModified(boolean state) {
+ //System.out.println("setting modified to " + state);
+ //new Exception().printStackTrace();
+ current.setModified(state);
+ calcModified();
+ }
+
+
+ protected void calcModified() {
+ modified = false;
+ for (int i = 0; i < codeCount; i++) {
+ if (code[i].isModified()) {
+ modified = true;
+ break;
+ }
+ }
+ editor.header.repaint();
+
+ if (Base.isMacOS()) {
+ // http://developer.apple.com/qa/qa2001/qa1146.html
+ Object modifiedParam = modified ? Boolean.TRUE : Boolean.FALSE;
+ editor.getRootPane().putClientProperty("windowModified", modifiedParam);
+ }
+ }
+
+
+ public boolean isModified() {
+ return modified;
+ }
+
+
+ /**
+ * Save all code in the current sketch.
+ */
+ public boolean save() throws IOException {
+ // make sure the user didn't hide the sketch folder
+ ensureExistence();
+
+ // first get the contents of the editor text area
+ if (current.isModified()) {
+ current.setProgram(editor.getText());
+ }
+
+ // don't do anything if not actually modified
+ //if (!modified) return false;
+
+ if (isReadOnly()) {
+ // if the files are read-only, need to first do a "save as".
+ Base.showMessage("Sketch is read-only",
+ "Some files are marked \"read-only\", so you'll\n" +
+ "need to re-save this sketch to another location.");
+ // if the user cancels, give up on the save()
+ if (!saveAs()) return false;
+ }
+
+ for (int i = 0; i < codeCount; i++) {
+ if (code[i].isModified()) code[i].save();
+ }
+ calcModified();
+ return true;
+ }
+
+
+ /**
+ * Handles 'Save As' for a sketch.
+ *
+ * This basically just duplicates the current sketch folder to
+ * a new location, and then calls 'Save'. (needs to take the current
+ * state of the open files and save them to the new folder..
+ * but not save over the old versions for the old sketch..)
+ *
+ * Also removes the previously-generated .class and .jar files,
+ * because they can cause trouble.
+ */
+ protected boolean saveAs() throws IOException {
+ String newParentDir = null;
+ String newName = null;
+
+ /*
+ JFileChooser fc = new JFileChooser();
+ fc.setDialogTitle("Save sketch folder as...");
+ if (isReadOnly() || isUntitled()) {
+ // default to the sketchbook folder
+ fc.setCurrentDirectory(new File(Preferences.get("sketchbook.path")));
+ } else {
+ // default to the parent folder of where this was
+ fc.setCurrentDirectory(folder.getParentFile());
+ }
+ // can't do this, will try to save into itself by default
+ //fc.setSelectedFile(folder);
+ int result = fc.showSaveDialog(editor);
+ if (result == JFileChooser.APPROVE_OPTION) {
+ File selection = fc.getSelectedFile();
+ newParentDir = selection.getParent();
+ newName = selection.getName();
+ }
+ */
+
+ // get new name for folder
+ FileDialog fd = new FileDialog(editor,
+ "Save sketch folder as...",
+ FileDialog.SAVE);
+ if (isReadOnly() || isUntitled()) {
+ // default to the sketchbook folder
+ fd.setDirectory(Preferences.get("sketchbook.path"));
+ } else {
+ // default to the parent folder of where this was
+ fd.setDirectory(folder.getParent());
+ }
+ String oldName = folder.getName();
+ fd.setFile(oldName);
+
+ fd.setVisible(true);
+ newParentDir = fd.getDirectory();
+ newName = fd.getFile();
+
+ // user canceled selection
+ if (newName == null) return false;
+ newName = Sketch.checkName(newName);
+
+ File newFolder = new File(newParentDir, newName);
+// String newPath = newFolder.getAbsolutePath();
+// String oldPath = folder.getAbsolutePath();
+
+// if (newPath.equals(oldPath)) {
+// return false; // Can't save a sketch over itself
+// }
+
+ // make sure there doesn't exist a tab with that name already
+ // but ignore this situation for the first tab, since it's probably being
+ // resaved (with the same name) to another location/folder.
+ for (int i = 1; i < codeCount; i++) {
+ if (newName.equals(code[i].getPrettyName())) {
+ Base.showMessage("Nope",
+ "You can't save the sketch as \"" + newName + "\"\n" +
+ "because the sketch already has a tab with that name.");
+ return false;
+ }
+ }
+
+ // check if the paths are identical
+ if (newFolder.equals(folder)) {
+ // just use "save" here instead, because the user will have received a
+ // message (from the operating system) about "do you want to replace?"
+ return save();
+ }
+
+ // check to see if the user is trying to save this sketch inside itself
+ try {
+ String newPath = newFolder.getCanonicalPath() + File.separator;
+ String oldPath = folder.getCanonicalPath() + File.separator;
+
+ if (newPath.indexOf(oldPath) == 0) {
+ Base.showWarning("How very Borges of you",
+ "You cannot save the sketch into a folder\n" +
+ "inside itself. This would go on forever.", null);
+ return false;
+ }
+ } catch (IOException e) { }
+
+ // if the new folder already exists, then need to remove
+ // its contents before copying everything over
+ // (user will have already been warned)
+ if (newFolder.exists()) {
+ Base.removeDir(newFolder);
+ }
+ // in fact, you can't do this on windows because the file dialog
+ // will instead put you inside the folder, but it happens on osx a lot.
+
+ // now make a fresh copy of the folder
+ newFolder.mkdirs();
+
+ // grab the contents of the current tab before saving
+ // first get the contents of the editor text area
+ if (current.isModified()) {
+ current.setProgram(editor.getText());
+ }
+
+ // save the other tabs to their new location
+ for (int i = 1; i < codeCount; i++) {
+ File newFile = new File(newFolder, code[i].getFileName());
+ code[i].saveAs(newFile);
+ }
+
+ // re-copy the data folder (this may take a while.. add progress bar?)
+ if (dataFolder.exists()) {
+ File newDataFolder = new File(newFolder, "data");
+ Base.copyDir(dataFolder, newDataFolder);
+ }
+
+ // re-copy the code folder
+ if (codeFolder.exists()) {
+ File newCodeFolder = new File(newFolder, "code");
+ Base.copyDir(codeFolder, newCodeFolder);
+ }
+
+ // copy custom applet.html file if one exists
+ // http://dev.processing.org/bugs/show_bug.cgi?id=485
+ File customHtml = new File(folder, "applet.html");
+ if (customHtml.exists()) {
+ File newHtml = new File(newFolder, "applet.html");
+ Base.copyFile(customHtml, newHtml);
+ }
+
+ // save the main tab with its new name
+ File newFile = new File(newFolder, newName + ".pde");
+ code[0].saveAs(newFile);
+
+ editor.handleOpenUnchecked(newFile.getPath(),
+ currentIndex,
+ editor.getSelectionStart(),
+ editor.getSelectionStop(),
+ editor.getScrollPosition());
+
+ // Name changed, rebuild the sketch menus
+ //editor.sketchbook.rebuildMenusAsync();
+ editor.base.rebuildSketchbookMenus();
+
+ // Make sure that it's not an untitled sketch
+ setUntitled(false);
+
+ // let Editor know that the save was successful
+ return true;
+ }
+
+
+ /**
+ * Prompt the user for a new file to the sketch, then call the
+ * other addFile() function to actually add it.
+ */
+ public void handleAddFile() {
+ // make sure the user didn't hide the sketch folder
+ ensureExistence();
+
+ // if read-only, give an error
+ if (isReadOnly()) {
+ // if the files are read-only, need to first do a "save as".
+ Base.showMessage("Sketch is Read-Only",
+ "Some files are marked \"read-only\", so you'll\n" +
+ "need to re-save the sketch in another location,\n" +
+ "and try again.");
+ return;
+ }
+
+ // get a dialog, select a file to add to the sketch
+ String prompt =
+ "Select an image or other data file to copy to your sketch";
+ //FileDialog fd = new FileDialog(new Frame(), prompt, FileDialog.LOAD);
+ FileDialog fd = new FileDialog(editor, prompt, FileDialog.LOAD);
+ fd.setVisible(true);
+
+ String directory = fd.getDirectory();
+ String filename = fd.getFile();
+ if (filename == null) return;
+
+ // copy the file into the folder. if people would rather
+ // it move instead of copy, they can do it by hand
+ File sourceFile = new File(directory, filename);
+
+ // now do the work of adding the file
+ boolean result = addFile(sourceFile);
+
+ if (result) {
+ editor.statusNotice("One file added to the sketch.");
+ }
+ }
+
+
+ /**
+ * Add a file to the sketch.
+ *
+ * .pde or .java files will be added to the sketch folder.
+ * .jar, .class, .dll, .jnilib, and .so files will all
+ * be added to the "code" folder.
+ * All other files will be added to the "data" folder.
+ *
+ * If they don't exist already, the "code" or "data" folder
+ * will be created.
+ *
+ * @return true if successful.
+ */
+ public boolean addFile(File sourceFile) {
+ String filename = sourceFile.getName();
+ File destFile = null;
+ String codeExtension = null;
+ boolean replacement = false;
+
+ // if the file appears to be code related, drop it
+ // into the code folder, instead of the data folder
+ if (filename.toLowerCase().endsWith(".class") ||
+ filename.toLowerCase().endsWith(".jar") ||
+ filename.toLowerCase().endsWith(".dll") ||
+ filename.toLowerCase().endsWith(".jnilib") ||
+ filename.toLowerCase().endsWith(".so")) {
+
+ //if (!codeFolder.exists()) codeFolder.mkdirs();
+ prepareCodeFolder();
+ destFile = new File(codeFolder, filename);
+
+ } else {
+ for (String extension : getExtensions()) {
+ String lower = filename.toLowerCase();
+ if (lower.endsWith("." + extension)) {
+ destFile = new File(this.folder, filename);
+ codeExtension = extension;
+ }
+ }
+ if (codeExtension == null) {
+ prepareDataFolder();
+ destFile = new File(dataFolder, filename);
+ }
+ }
+
+ // check whether this file already exists
+ if (destFile.exists()) {
+ Object[] options = { "OK", "Cancel" };
+ String prompt = "Replace the existing version of " + filename + "?";
+ int result = JOptionPane.showOptionDialog(editor,
+ prompt,
+ "Replace",
+ JOptionPane.YES_NO_OPTION,
+ JOptionPane.QUESTION_MESSAGE,
+ null,
+ options,
+ options[0]);
+ if (result == JOptionPane.YES_OPTION) {
+ replacement = true;
+ } else {
+ return false;
+ }
+ }
+
+ // If it's a replacement, delete the old file first,
+ // otherwise case changes will not be preserved.
+ // http://dev.processing.org/bugs/show_bug.cgi?id=969
+ if (replacement) {
+ boolean muchSuccess = destFile.delete();
+ if (!muchSuccess) {
+ Base.showWarning("Error adding file",
+ "Could not delete the existing '" +
+ filename + "' file.", null);
+ return false;
+ }
+ }
+
+ // make sure they aren't the same file
+ if ((codeExtension == null) && sourceFile.equals(destFile)) {
+ Base.showWarning("You can't fool me",
+ "This file has already been copied to the\n" +
+ "location from which where you're trying to add it.\n" +
+ "I ain't not doin nuthin'.", null);
+ return false;
+ }
+
+ // 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 (codeExtension != null) {
+ SketchCode newCode = new SketchCode(destFile, codeExtension);
+
+ if (replacement) {
+ replaceCode(newCode);
+
+ } else {
+ insertCode(newCode);
+ sortCode();
+ }
+ setCurrentCode(filename);
+ editor.header.repaint();
+ if (editor.untitled) { // TODO probably not necessary? problematic?
+ // Mark the new code as modified so that the sketch is saved
+ current.setModified(true);
+ }
+
+ } else {
+ if (editor.untitled) { // TODO probably not necessary? problematic?
+ // If a file has been added, mark the main code as modified so
+ // that the sketch is properly saved.
+ code[0].setModified(true);
+ }
+ }
+ return true;
+ }
+
+
+ /**
+ * Add import statements to the current tab for all of packages inside
+ * the specified jar file.
+ */
+ public void importLibrary(String jarPath) {
+ // make sure the user didn't hide the sketch folder
+ ensureExistence();
+
+ String list[] = Compiler.packageListFromClassPath(jarPath);
+
+ // import statements into the main sketch file (code[0])
+ // if the current code is a .java file, insert into current
+ //if (current.flavor == PDE) {
+ if (hasDefaultExtension(current)) {
+ setCurrentCode(0);
+ }
+ // could also scan the text in the file to see if each import
+ // statement is already in there, but if the user has the import
+ // commented out, then this will be a problem.
+ StringBuffer buffer = new StringBuffer();
+ for (int i = 0; i < list.length; i++) {
+ buffer.append("import ");
+ buffer.append(list[i]);
+ buffer.append(".*;\n");
+ }
+ buffer.append('\n');
+ buffer.append(editor.getText());
+ editor.setText(buffer.toString());
+ editor.setSelection(0, 0); // scroll to start
+ setModified(true);
+ }
+
+
+ /**
+ * Change what file is currently being edited. Changes the current tab index.
+ *
+ *
store the String for the text of the current file.
+ *
retrieve the String for the text of the new file.
+ *
change the text that's visible in the text area
+ *
+ */
+ public void setCurrentCode(int which) {
+ // if current is null, then this is the first setCurrent(0)
+ if ((currentIndex == which) && (current != null)) {
+ return;
+ }
+
+ // get the text currently being edited
+ if (current != null) {
+ current.setState(editor.getText(),
+ editor.getSelectionStart(),
+ editor.getSelectionStop(),
+ editor.getScrollPosition());
+ }
+
+ current = code[which];
+ currentIndex = which;
+
+ editor.setCode(current);
+ editor.header.rebuild();
+ }
+
+
+ /**
+ * Internal helper function to set the current tab based on a name.
+ * @param findName the file name (not pretty name) to be shown
+ */
+ protected void setCurrentCode(String findName) {
+ for (int i = 0; i < codeCount; i++) {
+ if (findName.equals(code[i].getFileName()) ||
+ findName.equals(code[i].getPrettyName())) {
+ setCurrentCode(i);
+ return;
+ }
+ }
+ }
+
+
+ /**
+ * Cleanup temporary files used during a build/run.
+ */
+ protected void cleanup() {
+ // if the java runtime is holding onto any files in the build dir, we
+ // won't be able to delete them, so we need to force a gc here
+ System.gc();
+
+ // note that we can't remove the builddir itself, otherwise
+ // the next time we start up, internal runs using Runner won't
+ // work because the build dir won't exist at startup, so the classloader
+ // will ignore the fact that that dir is in the CLASSPATH in run.sh
+ Base.removeDescendants(tempBuildFolder);
+ }
+
+
+ /**
+ * Preprocess, Compile, and Run the current code.
+ *
+ * There are three main parts to this process:
+ *
+ * (0. if not java, then use another 'engine'.. i.e. python)
+ *
+ * 1. do the p5 language preprocessing
+ * this creates a working .java file in a specific location
+ * better yet, just takes a chunk of java code and returns a
+ * new/better string editor can take care of saving this to a
+ * file location
+ *
+ * 2. compile the code from that location
+ * catching errors along the way
+ * placing it in a ready classpath, or .. ?
+ *
+ * 3. run the code
+ * needs to communicate location for window
+ * and maybe setup presentation space as well
+ * run externally if a code folder exists,
+ * or if more than one file is in the project
+ *
+ * X. afterwards, some of these steps need a cleanup function
+ *
+ */
+ protected String compile() throws RunnerException {
+ // make sure the user didn't hide the sketch folder
+ ensureExistence();
+
+ current.setProgram(editor.getText());
+
+ // TODO record history here
+ //current.history.record(program, SketchHistory.RUN);
+
+ // if an external editor is being used, need to grab the
+ // latest version of the code from the file.
+ if (Preferences.getBoolean("editor.external")) {
+ // history gets screwed by the open..
+ //String historySaved = history.lastRecorded;
+ //handleOpen(sketch);
+ //history.lastRecorded = historySaved;
+
+ // set current to null so that the tab gets updated
+ // http://dev.processing.org/bugs/show_bug.cgi?id=515
+ current = null;
+ // nuke previous files and settings, just get things loaded
+ load();
+ }
+
+ // in case there were any boogers left behind
+ // do this here instead of after exiting, since the exit
+ // can happen so many different ways.. and this will be
+ // better connected to the dataFolder stuff below.
+ cleanup();
+
+ // handle preprocessing the main file's code
+ return build(tempBuildFolder.getAbsolutePath());
+ }
+
+
+ /**
+ * Build all the code for this sketch.
+ *
+ * In an advanced program, the returned class name could be different,
+ * which is why the className is set based on the return value.
+ * A compilation error will burp up a RunnerException.
+ *
+ * Setting purty to 'true' will cause exception line numbers to be incorrect.
+ * Unless you know the code compiles, you should first run the preprocessor
+ * with purty set to false to make sure there are no errors, then once
+ * successful, re-export with purty set to true.
+ *
+ * @param buildPath Location to copy all the .java files
+ * @return null if compilation failed, main class name if not
+ */
+ public String preprocess(String buildPath) throws RunnerException {
+ // make sure the user didn't hide the sketch folder
+ ensureExistence();
+
+ String[] codeFolderPackages = null;
+ classPath = buildPath;
+
+ // figure out the contents of the code folder to see if there
+ // are files that need to be added to the imports
+ if (codeFolder.exists()) {
+ libraryPath = codeFolder.getAbsolutePath();
+
+ // get a list of .jar files in the "code" folder
+ // (class files in subfolders should also be picked up)
+ String codeFolderClassPath =
+ Compiler.contentsToClassPath(codeFolder);
+ // append the jar files in the code folder to the class path
+ classPath += File.pathSeparator + codeFolderClassPath;
+ // get list of packages found in those jars
+ codeFolderPackages =
+ Compiler.packageListFromClassPath(codeFolderClassPath);
+
+ } else {
+ libraryPath = "";
+ }
+
+ // 1. concatenate all .pde files to the 'main' pde
+ // store line number for starting point of each code bit
+
+ // Unfortunately, the header has to be written on a single line, because
+ // there's no way to determine how long it will be until the code has
+ // already been preprocessed. The header will vary in length based on
+ // the programming mode (STATIC, ACTIVE, or JAVA), which is determined
+ // by the preprocessor. So the preprocOffset for the primary class remains
+ // zero, even though it'd be nice to have a legitimate offset, and be able
+ // to remove the 'pretty' boolean for preproc.write().
+
+ StringBuffer bigCode = new StringBuffer();
+ int bigCount = 0;
+ for (SketchCode sc : code) {
+ if (sc.isExtension("pde")) {
+ sc.setPreprocOffset(bigCount);
+ bigCode.append(sc.getProgram());
+ bigCode.append('\n');
+ bigCount += sc.getLineCount();
+// if (sc != code[0]) {
+// sc.setPreprocName(null); // don't compile me
+// }
+ }
+ }
+
+ /*
+ String program = code[0].getProgram();
+ StringBuffer bigCode = new StringBuffer(program);
+ int bigCount = code[0].getLineCount();
+ bigCode.append('\n');
+
+ for (int i = 1; i < codeCount; i++) {
+ if (code[i].isExtension("pde")) {
+ code[i].setPreprocOffset(bigCount);
+ bigCode.append(code[i].getProgram());
+ bigCode.append('\n');
+ bigCount += code[i].getLineCount();
+ code[i].setPreprocName(null); // don't compile me
+ }
+ }
+ */
+
+ // Note that the headerOffset isn't applied until compile and run, because
+ // it only applies to the code after it's been written to the .java file.
+ int headerOffset = 0;
+ PdePreprocessor preprocessor = new PdePreprocessor();
+ try {
+ headerOffset = preprocessor.writePrefix(bigCode.toString(),
+ buildPath,
+ name,
+ codeFolderPackages);
+ } catch (FileNotFoundException fnfe) {
+ fnfe.printStackTrace();
+ String msg = "Build folder disappeared or could not be written";
+ throw new RunnerException(msg);
+ }
+
+ // 2. run preproc on that code using the sugg class name
+ // to create a single .java file and write to buildpath
+
+ String primaryClassName = null;
+
+ try {
+ // if (i != 0) preproc will fail if a pde file is not
+ // java mode, since that's required
+ String className = preprocessor.write();
+
+ if (className == null) {
+ throw new RunnerException("Could not find main class");
+ // this situation might be perfectly fine,
+ // (i.e. if the file is empty)
+ //System.out.println("No class found in " + code[i].name);
+ //System.out.println("(any code in that file will be ignored)");
+ //System.out.println();
+
+// } else {
+// code[0].setPreprocName(className + ".java");
+ }
+
+ // store this for the compiler and the runtime
+ primaryClassName = className;
+
+ } catch (antlr.RecognitionException re) {
+ // re also returns a column that we're not bothering with for now
+
+ // first assume that it's the main file
+ int errorFile = 0;
+ int errorLine = re.getLine() - 1;
+
+ // then search through for anyone else whose preprocName is null,
+ // since they've also been combined into the main pde.
+ for (int i = 1; i < codeCount; i++) {
+ if (code[i].isExtension("pde") &&
+ (code[i].getPreprocOffset() < errorLine)) {
+ // keep looping until the errorLine is past the offset
+ errorFile = i;
+ }
+ }
+ errorLine -= code[errorFile].getPreprocOffset();
+
+// System.out.println("i found this guy snooping around..");
+// System.out.println("whatcha want me to do with 'im boss?");
+// System.out.println(errorLine + " " + errorFile + " " + code[errorFile].getPreprocOffset());
+
+ String msg = re.getMessage();
+
+ if (msg.equals("expecting RCURLY, found 'null'")) {
+ // This can be a problem since the error is sometimes listed as a line
+ // that's actually past the number of lines. For instance, it might
+ // report "line 15" of a 14 line program. Added code to highlightLine()
+ // inside Editor to deal with this situation (since that code is also
+ // useful for other similar situations).
+ throw new RunnerException("Found one too many { characters " +
+ "without a } to match it.",
+ errorFile, errorLine, re.getColumn());
+ }
+
+ if (msg.indexOf("expecting RBRACK") != -1) {
+ System.err.println(msg);
+ throw new RunnerException("Syntax error, " +
+ "maybe a missing ] character?",
+ errorFile, errorLine, re.getColumn());
+ }
+
+ if (msg.indexOf("expecting SEMI") != -1) {
+ System.err.println(msg);
+ throw new RunnerException("Syntax error, " +
+ "maybe a missing semicolon?",
+ errorFile, errorLine, re.getColumn());
+ }
+
+ if (msg.indexOf("expecting RPAREN") != -1) {
+ System.err.println(msg);
+ throw new RunnerException("Syntax error, " +
+ "maybe a missing right parenthesis?",
+ errorFile, errorLine, re.getColumn());
+ }
+
+ if (msg.indexOf("preproc.web_colors") != -1) {
+ throw new RunnerException("A web color (such as #ffcc00) " +
+ "must be six digits.",
+ errorFile, errorLine, re.getColumn(), false);
+ }
+
+ //System.out.println("msg is " + msg);
+ throw new RunnerException(msg, errorFile,
+ errorLine, re.getColumn());
+
+ } catch (antlr.TokenStreamRecognitionException tsre) {
+ // while this seems to store line and column internally,
+ // there doesn't seem to be a method to grab it..
+ // so instead it's done using a regexp
+
+// System.err.println("and then she tells me " + tsre.toString());
+ // TODO not tested since removing ORO matcher.. ^ could be a problem
+ String mess = "^line (\\d+):(\\d+):\\s";
+
+ String[] matches = PApplet.match(tsre.toString(), mess);
+ if (matches != null) {
+ int errorLine = Integer.parseInt(matches[1]) - 1;
+ int errorColumn = Integer.parseInt(matches[2]);
+
+ int errorFile = 0;
+ for (int i = 1; i < codeCount; i++) {
+ if (code[i].isExtension("pde") &&
+ (code[i].getPreprocOffset() < errorLine)) {
+ errorFile = i;
+ }
+ }
+ errorLine -= code[errorFile].getPreprocOffset();
+
+ throw new RunnerException(tsre.getMessage(),
+ errorFile, errorLine, errorColumn);
+
+ } else {
+ // this is bad, defaults to the main class.. hrm.
+ String msg = tsre.toString();
+ throw new RunnerException(msg, 0, -1, -1);
+ }
+
+ } catch (RunnerException pe) {
+ // RunnerExceptions are caught here and re-thrown, so that they don't
+ // get lost in the more general "Exception" handler below.
+ throw pe;
+
+ } catch (Exception ex) {
+ // TODO better method for handling this?
+ System.err.println("Uncaught exception type:" + ex.getClass());
+ ex.printStackTrace();
+ throw new RunnerException(ex.toString());
+ }
+
+ // grab the imports from the code just preproc'd
+
+ importedLibraries = new ArrayList();
+ for (String item : preprocessor.getExtraImports()) {
+ // remove things up to the last dot
+ int dot = item.lastIndexOf('.');
+ // http://dev.processing.org/bugs/show_bug.cgi?id=1145
+ String entry = (dot == -1) ? item : item.substring(0, dot);
+ File libFolder = (File) Base.importToLibraryTable.get(entry);
+
+ if (libFolder != null) {
+ importedLibraries.add(libFolder);
+ classPath += Compiler.contentsToClassPath(libFolder);
+ libraryPath += File.pathSeparator + libFolder.getAbsolutePath();
+ }
+ }
+
+ // Finally, add the regular Java CLASSPATH
+ String javaClassPath = System.getProperty("java.class.path");
+ // Remove quotes if any.. An annoying (and frequent) Windows problem
+ if (javaClassPath.startsWith("\"") && javaClassPath.endsWith("\"")) {
+ javaClassPath = javaClassPath.substring(1, javaClassPath.length() - 1);
+ }
+ classPath += File.pathSeparator + javaClassPath;
+
+
+ // 3. then loop over the code[] and save each .java file
+
+ for (SketchCode sc : code) {
+ if (sc.isExtension("java")) {
+ // no pre-processing services necessary for java files
+ // just write the the contents of 'program' to a .java file
+ // into the build directory. uses byte stream and reader/writer
+ // shtuff so that unicode bunk is properly handled
+ String filename = sc.getFileName(); //code[i].name + ".java";
+ try {
+ Base.saveFile(sc.getProgram(), new File(buildPath, filename));
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw new RunnerException("Problem moving " + filename +
+ " to the build folder");
+ }
+// sc.setPreprocName(filename);
+
+ } else if (sc.isExtension("pde")) {
+ // The compiler and runner will need this to have a proper offset
+ sc.addPreprocOffset(headerOffset);
+ }
+ }
+ return primaryClassName;
+ }
+
+
+ /**
+ * Preprocess and compile all the code for this sketch.
+ *
+ * In an advanced program, the returned class name could be different,
+ * which is why the className is set based on the return value.
+ * A compilation error will burp up a RunnerException.
+ *
+ * @return null if compilation failed, main class name if not
+ */
+ public String build(String buildPath) throws RunnerException {
+ // run the preprocessor
+ String primaryClassName = preprocess(buildPath);
+
+ // compile the program. errors will happen as a RunnerException
+ // that will bubble up to whomever called build().
+ Compiler compiler = new Compiler();
+ if (compiler.compile(this, buildPath, primaryClassName)) {
+ return primaryClassName;
+ }
+ return null;
+ }
+
+
+ protected boolean exportApplet() throws Exception {
+ return exportApplet(new File(folder, "applet").getAbsolutePath());
+ }
+
+
+ /**
+ * Handle export to applet.
+ */
+ public boolean exportApplet(String appletPath) throws RunnerException, IOException {
+ // Make sure the user didn't hide the sketch folder
+ ensureExistence();
+
+ // Reload the code when an external editor is being used
+ if (Preferences.getBoolean("editor.external")) {
+ // nuke previous files and settings
+ load();
+ }
+
+ File appletFolder = new File(appletPath);
+ // Nuke the old applet folder because it can cause trouble
+ if (Preferences.getBoolean("export.delete_target_folder")) {
+ Base.removeDir(appletFolder);
+ }
+ // Create a fresh applet folder (needed before preproc is run below)
+ appletFolder.mkdirs();
+
+ Hashtable zipFileContents = new Hashtable();
+
+ // build the sketch
+ String foundName = build(appletFolder.getPath());
+
+ // (already reported) error during export, exit this function
+ if (foundName == null) return false;
+
+ // If name != exportSketchName, then that's weirdness
+ // BUG unfortunately, that can also be a bug in the preproc :(
+ if (!name.equals(foundName)) {
+ Base.showWarning("Error during export",
+ "Sketch name is " + name + " but the sketch\n" +
+ "name in the code was " + foundName, null);
+ return false;
+ }
+
+ int wide = PApplet.DEFAULT_WIDTH;
+ int high = PApplet.DEFAULT_HEIGHT;
+ String renderer = "";
+
+ // This matches against any uses of the size() function, whether numbers
+ // or variables or whatever. This way, no warning is shown if size() isn't
+ // actually used in the applet, which is the case especially for anyone
+ // who is cutting/pasting from the reference.
+ String sizeRegex =
+ "(?:^|\\s|;)size\\s*\\(\\s*(\\S+)\\s*,\\s*(\\d+),?\\s*([^\\)]*)\\s*\\)";
+
+ String scrubbed = scrubComments(code[0].getProgram());
+ String[] matches = PApplet.match(scrubbed, sizeRegex);
+
+ if (matches != null) {
+ try {
+ wide = Integer.parseInt(matches[1]);
+ high = Integer.parseInt(matches[2]);
+
+ // Adding back the trim() for 0136 to handle Bug #769
+ if (matches.length == 4) renderer = matches[3].trim();
+
+ } catch (NumberFormatException e) {
+ // found a reference to size, but it didn't
+ // seem to contain numbers
+ final String message =
+ "The size of this applet could not automatically be\n" +
+ "determined from your code. You'll have to edit the\n" +
+ "HTML file to set the size of the applet.\n" +
+ "Use only numeric values (not variables) for the size()\n" +
+ "command. See the size() reference for an explanation.";
+
+ Base.showWarning("Could not find applet size", message, null);
+ }
+ } // else no size() command found
+
+ // Grab the Javadoc-style description from the main code.
+ // Originally tried to grab this with a regexp matcher, but it wouldn't
+ // span over multiple lines for the match. This could prolly be forced,
+ // but since that's the case better just to parse by hand.
+ StringBuffer dbuffer = new StringBuffer();
+ String lines[] = PApplet.split(code[0].getProgram(), '\n');
+ for (int i = 0; i < lines.length; i++) {
+ if (lines[i].trim().startsWith("/**")) { // this is our comment
+ // some smartass put the whole thing on the same line
+ //if (lines[j].indexOf("*/") != -1) break;
+
+ for (int j = i+1; j < lines.length; j++) {
+ if (lines[j].trim().endsWith("*/")) {
+ // remove the */ from the end, and any extra *s
+ // in case there's also content on this line
+ // nah, don't bother.. make them use the three lines
+ break;
+ }
+
+ int offset = 0;
+ while ((offset < lines[j].length()) &&
+ ((lines[j].charAt(offset) == '*') ||
+ (lines[j].charAt(offset) == ' '))) {
+ offset++;
+ }
+ // insert the return into the html to help w/ line breaks
+ dbuffer.append(lines[j].substring(offset) + "\n");
+ }
+ }
+ }
+ String description = dbuffer.toString();
+
+ // Add links to all the code
+ StringBuffer sources = new StringBuffer();
+ for (int i = 0; i < codeCount; i++) {
+ sources.append("" +
+ code[i].getPrettyName() + " ");
+ }
+
+ // Copy the source files to the target, since we like
+ // to encourage people to share their code
+ for (int i = 0; i < codeCount; i++) {
+ try {
+ File exportedSource = new File(appletFolder, code[i].getFileName());
+ //Base.copyFile(code[i].getFile(), exportedSource);
+ code[i].copyTo(exportedSource);
+
+ } catch (IOException e) {
+ e.printStackTrace(); // ho hum, just move on...
+ }
+ }
+
+ // Use separate jarfiles whenever a library or code folder is in use.
+ boolean separateJar =
+ Preferences.getBoolean("export.applet.separate_jar_files") ||
+ codeFolder.exists() ||
+ (libraryPath.length() != 0);
+
+ // Copy the loading gif to the applet
+ String LOADING_IMAGE = "loading.gif";
+ // Check if the user already has their own loader image
+ File loadingImage = new File(folder, LOADING_IMAGE);
+ if (!loadingImage.exists()) {
+ File skeletonFolder = new File(Base.getContentFile("lib"), "export");
+ loadingImage = new File(skeletonFolder, LOADING_IMAGE);
+ }
+ Base.copyFile(loadingImage, new File(appletFolder, LOADING_IMAGE));
+
+ // Create new .jar file
+ FileOutputStream zipOutputFile =
+ new FileOutputStream(new File(appletFolder, name + ".jar"));
+ ZipOutputStream zos = new ZipOutputStream(zipOutputFile);
+ ZipEntry entry;
+
+ StringBuffer archives = new StringBuffer();
+ archives.append(name + ".jar");
+
+ // Add the manifest file
+ addManifest(zos);
+
+ // add the contents of the code folder to the jar
+ // unpacks all jar files, unless multi jar files selected in prefs
+ if (codeFolder.exists()) {
+ String includes = Compiler.contentsToClassPath(codeFolder);
+ String[] codeList = PApplet.splitTokens(includes, File.separator);
+ String cp = "";
+ for (int i = 0; i < codeList.length; i++) {
+ if (codeList[i].toLowerCase().endsWith(".jar") ||
+ codeList[i].toLowerCase().endsWith(".zip")) {
+ if (separateJar) {
+ File exportFile = new File(codeFolder, codeList[i]);
+ String exportFilename = exportFile.getName();
+ Base.copyFile(exportFile, new File(appletFolder, exportFilename));
+ } else {
+ cp += codeList[i] + File.pathSeparatorChar;
+ //packClassPathIntoZipFile(cp, zos);
+ }
+ }
+ }
+ if (!separateJar) {
+ packClassPathIntoZipFile(cp, zos, zipFileContents);
+ }
+ }
+
+ // add contents of 'library' folders to the jar file
+ // if a file called 'export.txt' is in there, it contains
+ // a list of the files that should be exported.
+ // otherwise, all files are exported.
+ for (File libraryFolder : importedLibraries) {
+// Enumeration en = importedLibraries.elements();
+// while (en.hasMoreElements()) {
+ // in the list is a File object that points the
+ // library sketch's "library" folder
+// File libraryFolder = (File)en.nextElement();
+ File exportSettings = new File(libraryFolder, "export.txt");
+ Hashtable exportTable = readSettings(exportSettings);
+ String appletList = (String) exportTable.get("applet");
+ String exportList[] = null;
+ if (appletList != null) {
+ exportList = PApplet.splitTokens(appletList, ", ");
+ } else {
+ exportList = libraryFolder.list();
+ }
+ for (int i = 0; i < exportList.length; i++) {
+ if (exportList[i].equals(".") ||
+ exportList[i].equals("..")) continue;
+
+ exportList[i] = PApplet.trim(exportList[i]);
+ if (exportList[i].equals("")) continue;
+
+ File exportFile = new File(libraryFolder, exportList[i]);
+ if (!exportFile.exists()) {
+ System.err.println("File " + exportList[i] + " does not exist");
+
+ } else if (exportFile.isDirectory()) {
+ System.err.println("Ignoring sub-folder \"" + exportList[i] + "\"");
+
+ } else if (exportFile.getName().toLowerCase().endsWith(".zip") ||
+ exportFile.getName().toLowerCase().endsWith(".jar")) {
+ if (separateJar) {
+ String exportFilename = exportFile.getName();
+ Base.copyFile(exportFile, new File(appletFolder, exportFilename));
+ if (renderer.equals("OPENGL") &&
+ exportFilename.indexOf("natives") != -1) {
+ // don't add these to the archives list
+ } else {
+ archives.append("," + exportFilename);
+ }
+ } else {
+ String path = exportFile.getAbsolutePath();
+ packClassPathIntoZipFile(path, zos, zipFileContents);
+ }
+
+ } else { // just copy the file over.. prolly a .dll or something
+ Base.copyFile(exportFile,
+ new File(appletFolder, exportFile.getName()));
+ }
+ }
+ }
+
+ File bagelJar = Base.isMacOS() ?
+ Base.getContentFile("core.jar") :
+ Base.getContentFile("lib/core.jar");
+ if (separateJar) {
+ Base.copyFile(bagelJar, new File(appletFolder, "core.jar"));
+ archives.append(",core.jar");
+ } else {
+ String bagelJarPath = bagelJar.getAbsolutePath();
+ packClassPathIntoZipFile(bagelJarPath, zos, zipFileContents);
+ }
+
+ if (dataFolder.exists()) {
+ String dataFiles[] = Base.listFiles(dataFolder, false);
+ int offset = folder.getAbsolutePath().length() + 1;
+ for (int i = 0; i < dataFiles.length; i++) {
+ if (Base.isWindows()) {
+ dataFiles[i] = dataFiles[i].replace('\\', '/');
+ }
+ File dataFile = new File(dataFiles[i]);
+ if (dataFile.isDirectory()) continue;
+
+ // don't export hidden files
+ // skipping dot prefix removes all: . .. .DS_Store
+ if (dataFile.getName().charAt(0) == '.') continue;
+
+ entry = new ZipEntry(dataFiles[i].substring(offset));
+ zos.putNextEntry(entry);
+ zos.write(Base.loadBytesRaw(dataFile));
+ zos.closeEntry();
+ }
+ }
+
+ // add the project's .class files to the jar
+ // just grabs everything from the build directory
+ // since there may be some inner classes
+ // (add any .class files from the applet dir, then delete them)
+ // TODO this needs to be recursive (for packages)
+ String classfiles[] = appletFolder.list();
+ for (int i = 0; i < classfiles.length; i++) {
+ if (classfiles[i].endsWith(".class")) {
+ entry = new ZipEntry(classfiles[i]);
+ zos.putNextEntry(entry);
+ zos.write(Base.loadBytesRaw(new File(appletFolder, classfiles[i])));
+ zos.closeEntry();
+ }
+ }
+
+ // remove the .class files from the applet folder. if they're not
+ // removed, the msjvm will complain about an illegal access error,
+ // since the classes are outside the jar file.
+ for (int i = 0; i < classfiles.length; i++) {
+ if (classfiles[i].endsWith(".class")) {
+ File deadguy = new File(appletFolder, classfiles[i]);
+ if (!deadguy.delete()) {
+ Base.showWarning("Could not delete",
+ classfiles[i] + " could not \n" +
+ "be deleted from the applet folder. \n" +
+ "You'll need to remove it by hand.", null);
+ }
+ }
+ }
+
+ // close up the jar file
+ zos.flush();
+ zos.close();
+
+ //
+
+ // convert the applet template
+ // @@sketch@@, @@width@@, @@height@@, @@archive@@, @@source@@
+ // and now @@description@@
+
+ File htmlOutputFile = new File(appletFolder, "index.html");
+ // UTF-8 fixes http://dev.processing.org/bugs/show_bug.cgi?id=474
+ PrintWriter htmlWriter = PApplet.createWriter(htmlOutputFile);
+
+ InputStream is = null;
+ // if there is an applet.html file in the sketch folder, use that
+ File customHtml = new File(folder, "applet.html");
+ if (customHtml.exists()) {
+ is = new FileInputStream(customHtml);
+ }
+ if (is == null) {
+ if (renderer.equals("OPENGL")) {
+ is = Base.getLibStream("export/applet-opengl.html");
+ } else {
+ is = Base.getLibStream("export/applet.html");
+ }
+ }
+ BufferedReader reader = PApplet.createReader(is);
+
+ String line = null;
+ while ((line = reader.readLine()) != null) {
+ if (line.indexOf("@@") != -1) {
+ StringBuffer sb = new StringBuffer(line);
+ int index = 0;
+ while ((index = sb.indexOf("@@sketch@@")) != -1) {
+ sb.replace(index, index + "@@sketch@@".length(),
+ name);
+ }
+ while ((index = sb.indexOf("@@source@@")) != -1) {
+ sb.replace(index, index + "@@source@@".length(),
+ sources.toString());
+ }
+ while ((index = sb.indexOf("@@archive@@")) != -1) {
+ sb.replace(index, index + "@@archive@@".length(),
+ archives.toString());
+ }
+ while ((index = sb.indexOf("@@width@@")) != -1) {
+ sb.replace(index, index + "@@width@@".length(),
+ String.valueOf(wide));
+ }
+ while ((index = sb.indexOf("@@height@@")) != -1) {
+ sb.replace(index, index + "@@height@@".length(),
+ String.valueOf(high));
+ }
+ while ((index = sb.indexOf("@@description@@")) != -1) {
+ sb.replace(index, index + "@@description@@".length(),
+ description);
+ }
+ line = sb.toString();
+ }
+ htmlWriter.println(line);
+ }
+
+ reader.close();
+ htmlWriter.flush();
+ htmlWriter.close();
+
+ return true;
+ }
+
+
+ /**
+ * Replace all commented portions of a given String as spaces.
+ * Utility function used here and in the preprocessor.
+ */
+ static public String scrubComments(String what) {
+ char p[] = what.toCharArray();
+
+ int index = 0;
+ while (index < p.length) {
+ // for any double slash comments, ignore until the end of the line
+ if ((p[index] == '/') &&
+ (index < p.length - 1) &&
+ (p[index+1] == '/')) {
+ p[index++] = ' ';
+ p[index++] = ' ';
+ while ((index < p.length) &&
+ (p[index] != '\n')) {
+ p[index++] = ' ';
+ }
+
+ // check to see if this is the start of a new multiline comment.
+ // if it is, then make sure it's actually terminated somewhere.
+ } else if ((p[index] == '/') &&
+ (index < p.length - 1) &&
+ (p[index+1] == '*')) {
+ p[index++] = ' ';
+ p[index++] = ' ';
+ boolean endOfRainbow = false;
+ while (index < p.length - 1) {
+ if ((p[index] == '*') && (p[index+1] == '/')) {
+ p[index++] = ' ';
+ p[index++] = ' ';
+ endOfRainbow = true;
+ break;
+
+ } else {
+ index++;
+ }
+ }
+ if (!endOfRainbow) {
+ throw new RuntimeException("Missing the */ from the end of a " +
+ "/* comment */");
+ }
+ } else { // any old character, move along
+ index++;
+ }
+ }
+ return new String(p);
+ }
+
+
+ public boolean exportApplicationPrompt() throws IOException, RunnerException {
+ JPanel panel = new JPanel();
+ panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
+ panel.add(Box.createVerticalStrut(6));
+
+ //Box panel = Box.createVerticalBox();
+
+ //Box labelBox = Box.createHorizontalBox();
+// String msg = "Click Export to Application to create a standalone, " +
+// "double-clickable application for the selected plaforms.";
+
+// String msg = "Export to Application creates a standalone, \n" +
+// "double-clickable application for the selected plaforms.";
+ String line1 = "Export to Application creates double-clickable,";
+ String line2 = "standalone applications for the selected plaforms.";
+ JLabel label1 = new JLabel(line1, SwingConstants.CENTER);
+ JLabel label2 = new JLabel(line2, SwingConstants.CENTER);
+ label1.setAlignmentX(Component.LEFT_ALIGNMENT);
+ label2.setAlignmentX(Component.LEFT_ALIGNMENT);
+// label1.setAlignmentX();
+// label2.setAlignmentX(0);
+ panel.add(label1);
+ panel.add(label2);
+ int wide = label2.getPreferredSize().width;
+ panel.add(Box.createVerticalStrut(12));
+
+ final JCheckBox windowsButton = new JCheckBox("Windows");
+ //windowsButton.setMnemonic(KeyEvent.VK_W);
+ windowsButton.setSelected(Preferences.getBoolean("export.application.platform.windows"));
+ windowsButton.addItemListener(new ItemListener() {
+ public void itemStateChanged(ItemEvent e) {
+ Preferences.setBoolean("export.application.platform.windows", windowsButton.isSelected());
+ }
+ });
+
+ final JCheckBox macosxButton = new JCheckBox("Mac OS X");
+ //macosxButton.setMnemonic(KeyEvent.VK_M);
+ macosxButton.setSelected(Preferences.getBoolean("export.application.platform.macosx"));
+ macosxButton.addItemListener(new ItemListener() {
+ public void itemStateChanged(ItemEvent e) {
+ Preferences.setBoolean("export.application.platform.macosx", macosxButton.isSelected());
+ }
+ });
+
+ final JCheckBox linuxButton = new JCheckBox("Linux");
+ //linuxButton.setMnemonic(KeyEvent.VK_L);
+ linuxButton.setSelected(Preferences.getBoolean("export.application.platform.linux"));
+ linuxButton.addItemListener(new ItemListener() {
+ public void itemStateChanged(ItemEvent e) {
+ Preferences.setBoolean("export.application.platform.linux", linuxButton.isSelected());
+ }
+ });
+
+ JPanel platformPanel = new JPanel();
+ //platformPanel.setLayout(new BoxLayout(platformPanel, BoxLayout.X_AXIS));
+ platformPanel.add(windowsButton);
+ platformPanel.add(Box.createHorizontalStrut(6));
+ platformPanel.add(macosxButton);
+ platformPanel.add(Box.createHorizontalStrut(6));
+ platformPanel.add(linuxButton);
+ platformPanel.setBorder(new TitledBorder("Platforms"));
+ //Dimension goodIdea = new Dimension(wide, platformPanel.getPreferredSize().height);
+ //platformPanel.setMaximumSize(goodIdea);
+ wide = Math.max(wide, platformPanel.getPreferredSize().width);
+ platformPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
+ panel.add(platformPanel);
+
+// Box indentPanel = Box.createHorizontalBox();
+// indentPanel.add(Box.createHorizontalStrut(new JCheckBox().getPreferredSize().width));
+ final JCheckBox showStopButton = new JCheckBox("Show a Stop button");
+ //showStopButton.setMnemonic(KeyEvent.VK_S);
+ showStopButton.setSelected(Preferences.getBoolean("export.application.stop"));
+ showStopButton.addItemListener(new ItemListener() {
+ public void itemStateChanged(ItemEvent e) {
+ Preferences.setBoolean("export.application.stop", showStopButton.isSelected());
+ }
+ });
+ showStopButton.setEnabled(Preferences.getBoolean("export.application.fullscreen"));
+ showStopButton.setBorder(new EmptyBorder(3, 13, 6, 13));
+// indentPanel.add(showStopButton);
+// indentPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
+
+ final JCheckBox fullScreenButton = new JCheckBox("Full Screen (Present mode)");
+ //fullscreenButton.setMnemonic(KeyEvent.VK_F);
+ fullScreenButton.setSelected(Preferences.getBoolean("export.application.fullscreen"));
+ fullScreenButton.addItemListener(new ItemListener() {
+ public void itemStateChanged(ItemEvent e) {
+ boolean sal = fullScreenButton.isSelected();
+ Preferences.setBoolean("export.application.fullscreen", sal);
+ showStopButton.setEnabled(sal);
+ }
+ });
+ fullScreenButton.setBorder(new EmptyBorder(3, 13, 3, 13));
+
+ JPanel optionPanel = new JPanel();
+ optionPanel.setLayout(new BoxLayout(optionPanel, BoxLayout.Y_AXIS));
+ optionPanel.add(fullScreenButton);
+ optionPanel.add(showStopButton);
+// optionPanel.add(indentPanel);
+ optionPanel.setBorder(new TitledBorder("Options"));
+ wide = Math.max(wide, platformPanel.getPreferredSize().width);
+ //goodIdea = new Dimension(wide, optionPanel.getPreferredSize().height);
+ optionPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
+ //optionPanel.setMaximumSize(goodIdea);
+ panel.add(optionPanel);
+
+ Dimension good;
+ //label1, label2, platformPanel, optionPanel
+ good = new Dimension(wide, label1.getPreferredSize().height);
+ label1.setMaximumSize(good);
+ good = new Dimension(wide, label2.getPreferredSize().height);
+ label2.setMaximumSize(good);
+ good = new Dimension(wide, platformPanel.getPreferredSize().height);
+ platformPanel.setMaximumSize(good);
+ good = new Dimension(wide, optionPanel.getPreferredSize().height);
+ optionPanel.setMaximumSize(good);
+
+// JPanel actionPanel = new JPanel();
+// optionPanel.setLayout(new BoxLayout(optionPanel, BoxLayout.X_AXIS));
+// optionPanel.add(Box.createHorizontalGlue());
+
+// final JDialog frame = new JDialog(editor, "Export to Application");
+
+// JButton cancelButton = new JButton("Cancel");
+// cancelButton.addActionListener(new ActionListener() {
+// public void actionPerformed(ActionEvent e) {
+// frame.dispose();
+// return false;
+// }
+// });
+
+ // Add the buttons in platform-specific order
+// if (PApplet.platform == PConstants.MACOSX) {
+// optionPanel.add(cancelButton);
+// optionPanel.add(exportButton);
+// } else {
+// optionPanel.add(exportButton);
+// optionPanel.add(cancelButton);
+// }
+ String[] options = { "Export", "Cancel" };
+ final JOptionPane optionPane = new JOptionPane(panel,
+ JOptionPane.PLAIN_MESSAGE,
+ //JOptionPane.QUESTION_MESSAGE,
+ JOptionPane.YES_NO_OPTION,
+ null,
+ options,
+ options[0]);
+
+ final JDialog dialog = new JDialog(editor, "Export Options", true);
+ dialog.setContentPane(optionPane);
+
+ optionPane.addPropertyChangeListener(new PropertyChangeListener() {
+ public void propertyChange(PropertyChangeEvent e) {
+ String prop = e.getPropertyName();
+
+ if (dialog.isVisible() &&
+ (e.getSource() == optionPane) &&
+ (prop.equals(JOptionPane.VALUE_PROPERTY))) {
+ //If you were going to check something
+ //before closing the window, you'd do
+ //it here.
+ dialog.setVisible(false);
+ }
+ }
+ });
+ dialog.pack();
+ dialog.setResizable(false);
+
+ Rectangle bounds = editor.getBounds();
+ dialog.setLocation(bounds.x + (bounds.width - dialog.getSize().width) / 2,
+ bounds.y + (bounds.height - dialog.getSize().height) / 2);
+ dialog.setVisible(true);
+
+ Object value = optionPane.getValue();
+ if (value.equals(options[0])) {
+ return exportApplication();
+ } else if (value.equals(options[1]) || value.equals(new Integer(-1))) {
+ // closed window by hitting Cancel or ESC
+ editor.statusNotice("Export to Application canceled.");
+ }
+ return false;
+ }
+
+
+ /**
+ * Export to application via GUI.
+ */
+ protected boolean exportApplication() throws IOException, RunnerException {
+ if (Preferences.getBoolean("export.application.platform.windows")) {
+ String windowsPath =
+ new File(folder, "application.windows").getAbsolutePath();
+ if (!exportApplication(windowsPath, PConstants.WINDOWS)) {
+ return false;
+ }
+ }
+ if (Preferences.getBoolean("export.application.platform.macosx")) {
+ String macosxPath =
+ new File(folder, "application.macosx").getAbsolutePath();
+ if (!exportApplication(macosxPath, PConstants.MACOSX)) {
+ return false;
+ }
+ }
+ if (Preferences.getBoolean("export.application.platform.linux")) {
+ String linuxPath =
+ new File(folder, "application.linux").getAbsolutePath();
+ if (!exportApplication(linuxPath, PConstants.LINUX)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+ /**
+ * Export to application without GUI.
+ */
+ public boolean exportApplication(String destPath,
+ int exportPlatform) throws IOException, RunnerException {
+ // make sure the user didn't hide the sketch folder
+ ensureExistence();
+
+ // fix for issue posted on the board. make sure that the code
+ // is reloaded when exporting and an external editor is being used.
+ if (Preferences.getBoolean("editor.external")) {
+ // don't do from the command line
+ if (editor != null) {
+ // nuke previous files and settings
+ load();
+ }
+ }
+
+ File destFolder = new File(destPath);
+ if (Preferences.getBoolean("export.delete_target_folder")) {
+ Base.removeDir(destFolder);
+ }
+ destFolder.mkdirs();
+
+ // build the sketch
+ String foundName = build(destFolder.getPath());
+
+ // (already reported) error during export, exit this function
+ if (foundName == null) return false;
+
+ // if name != exportSketchName, then that's weirdness
+ // BUG unfortunately, that can also be a bug in the preproc :(
+ if (!name.equals(foundName)) {
+ Base.showWarning("Error during export",
+ "Sketch name is " + name + " but the sketch\n" +
+ "name in the code was " + foundName, null);
+ return false;
+ }
+
+
+ /// figure out where the jar files will be placed
+
+ File jarFolder = new File(destFolder, "lib");
+
+
+ /// where all the skeleton info lives
+
+ File skeletonFolder = new File(Base.getContentFile("lib"), "export");
+
+ /// on macosx, need to copy .app skeleton since that's
+ /// also where the jar files will be placed
+ File dotAppFolder = null;
+ if (exportPlatform == PConstants.MACOSX) {
+ dotAppFolder = new File(destFolder, name + ".app");
+ String APP_SKELETON = "skeleton.app";
+ //File dotAppSkeleton = new File(folder, APP_SKELETON);
+ File dotAppSkeleton = new File(skeletonFolder, APP_SKELETON);
+ Base.copyDir(dotAppSkeleton, dotAppFolder);
+
+ String stubName = "Contents/MacOS/JavaApplicationStub";
+ // need to set the stub to executable
+ // will work on osx or *nix, but just dies on windows, oh well..
+ if (Base.isWindows()) {
+ File warningFile = new File(destFolder, "readme.txt");
+ PrintWriter pw = PApplet.createWriter(warningFile);
+ pw.println("This application was created on Windows, which does not");
+ pw.println("properly support setting files as \"executable\",");
+ pw.println("a necessity for applications on Mac OS X.");
+ pw.println();
+ pw.println("To fix this, use the Terminal on Mac OS X, and from this");
+ pw.println("directory, type the following:");
+ pw.println();
+ pw.println("chmod +x " + dotAppFolder.getName() + "/" + stubName);
+ pw.flush();
+ pw.close();
+
+ } else {
+ File stubFile = new File(dotAppFolder, stubName);
+ String stubPath = stubFile.getAbsolutePath();
+ Runtime.getRuntime().exec(new String[] { "chmod", "+x", stubPath });
+ }
+
+ // set the jar folder to a different location than windows/linux
+ jarFolder = new File(dotAppFolder, "Contents/Resources/Java");
+ }
+
+
+ /// make the jar folder (windows and linux)
+
+ if (!jarFolder.exists()) jarFolder.mkdirs();
+
+
+ /// on windows, copy the exe file
+
+ if (exportPlatform == PConstants.WINDOWS) {
+ Base.copyFile(new File(skeletonFolder, "application.exe"),
+ new File(destFolder, this.name + ".exe"));
+ }
+
+
+ /// start copying all jar files
+
+ Vector jarListVector = new Vector();
+
+
+ /// create the main .jar file
+
+ Hashtable zipFileContents = new Hashtable();
+
+ FileOutputStream zipOutputFile =
+ new FileOutputStream(new File(jarFolder, name + ".jar"));
+ ZipOutputStream zos = new ZipOutputStream(zipOutputFile);
+ ZipEntry entry;
+
+ // add the manifest file so that the .jar can be double clickable
+ addManifest(zos);
+
+ // add the project's .class files to the jar
+ // (just grabs everything from the build directory,
+ // since there may be some inner classes)
+ // TODO this needs to be recursive (for packages)
+ String classfiles[] = destFolder.list();
+ for (int i = 0; i < classfiles.length; i++) {
+ if (classfiles[i].endsWith(".class")) {
+ entry = new ZipEntry(classfiles[i]);
+ zos.putNextEntry(entry);
+ zos.write(Base.loadBytesRaw(new File(destFolder, classfiles[i])));
+ zos.closeEntry();
+ }
+ }
+
+ // add the data folder to the main jar file
+ if (dataFolder.exists()) {
+ String dataFiles[] = Base.listFiles(dataFolder, false);
+ int offset = folder.getAbsolutePath().length() + 1;
+ for (int i = 0; i < dataFiles.length; i++) {
+ if (Base.isWindows()) {
+ dataFiles[i] = dataFiles[i].replace('\\', '/');
+ }
+ File dataFile = new File(dataFiles[i]);
+ if (dataFile.isDirectory()) continue;
+
+ // don't export hidden files
+ // skipping dot prefix removes all: . .. .DS_Store
+ if (dataFile.getName().charAt(0) == '.') continue;
+
+ entry = new ZipEntry(dataFiles[i].substring(offset));
+ zos.putNextEntry(entry);
+ zos.write(Base.loadBytesRaw(dataFile));
+ zos.closeEntry();
+ }
+ }
+
+ // add the contents of the code folder to the jar
+ if (codeFolder.exists()) {
+ String includes = Compiler.contentsToClassPath(codeFolder);
+ // Use tokens to get rid of extra blanks, which causes huge exports
+ String[] codeList = PApplet.splitTokens(includes, File.separator);
+ String cp = "";
+ for (int i = 0; i < codeList.length; i++) {
+ if (codeList[i].toLowerCase().endsWith(".jar") ||
+ codeList[i].toLowerCase().endsWith(".zip")) {
+ File exportFile = new File(codeFolder, codeList[i]);
+ String exportFilename = exportFile.getName();
+ Base.copyFile(exportFile, new File(jarFolder, exportFilename));
+ jarListVector.add(exportFilename);
+ } else {
+ cp += codeList[i] + File.separatorChar;
+ }
+ }
+ packClassPathIntoZipFile(cp, zos, zipFileContents);
+ }
+
+ zos.flush();
+ zos.close();
+
+ jarListVector.add(name + ".jar");
+
+
+ /// add core.jar to the jar destination folder
+
+ File bagelJar = Base.isMacOS() ?
+ Base.getContentFile("core.jar") :
+ Base.getContentFile("lib/core.jar");
+ Base.copyFile(bagelJar, new File(jarFolder, "core.jar"));
+ jarListVector.add("core.jar");
+
+
+ /// add contents of 'library' folders to the export
+
+ // if a file called 'export.txt' is in there, it contains
+ // a list of the files that should be exported.
+ // otherwise, all files are exported.
+ for (File libraryFolder : importedLibraries) {
+ //System.out.println(libraryFolder + " " + libraryFolder.getAbsolutePath());
+ // in the list is a File object that points the
+ // library sketch's "library" folder
+ File exportSettings = new File(libraryFolder, "export.txt");
+ Hashtable exportTable = readSettings(exportSettings);
+ String commaList = null;
+ String exportList[] = null;
+
+ // first check to see if there's something like application.blargh
+ if (exportPlatform == PConstants.MACOSX) {
+ commaList = (String) exportTable.get("application.macosx");
+ } else if (exportPlatform == PConstants.WINDOWS) {
+ commaList = (String) exportTable.get("application.windows");
+ } else if (exportPlatform == PConstants.LINUX) {
+ commaList = (String) exportTable.get("application.linux");
+ } else {
+ // next check to see if something for 'application' is specified
+ commaList = (String) exportTable.get("application");
+ }
+ if (commaList == null) {
+ // otherwise just dump the whole folder
+ exportList = libraryFolder.list();
+ } else {
+ exportList = PApplet.splitTokens(commaList, ", ");
+ }
+
+ // add each item from the library folder / export list to the output
+ for (int i = 0; i < exportList.length; i++) {
+ if (exportList[i].equals(".") ||
+ exportList[i].equals("..")) continue;
+
+ exportList[i] = PApplet.trim(exportList[i]);
+ if (exportList[i].equals("")) continue;
+
+ File exportFile = new File(libraryFolder, exportList[i]);
+ if (!exportFile.exists()) {
+ System.err.println("File " + exportList[i] + " does not exist");
+
+ } else if (exportFile.isDirectory()) {
+ System.err.println("Ignoring sub-folder \"" + exportList[i] + "\"");
+
+ } else if (exportFile.getName().toLowerCase().endsWith(".zip") ||
+ exportFile.getName().toLowerCase().endsWith(".jar")) {
+ //packClassPathIntoZipFile(exportFile.getAbsolutePath(), zos);
+ Base.copyFile(exportFile, new File(jarFolder, exportList[i]));
+ jarListVector.add(exportList[i]);
+
+ } else if ((exportPlatform == PConstants.MACOSX) &&
+ (exportFile.getName().toLowerCase().endsWith(".jnilib"))) {
+ // jnilib files can be placed in Contents/Resources/Java
+ Base.copyFile(exportFile, new File(jarFolder, exportList[i]));
+
+ } else {
+ // copy the file to the main directory.. prolly a .dll or something
+ Base.copyFile(exportFile,
+ new File(destFolder, exportFile.getName()));
+ }
+ }
+ }
+
+
+ /// create platform-specific CLASSPATH based on included jars
+
+ String jarList[] = new String[jarListVector.size()];
+ jarListVector.copyInto(jarList);
+ StringBuffer exportClassPath = new StringBuffer();
+
+ if (exportPlatform == PConstants.MACOSX) {
+ for (int i = 0; i < jarList.length; i++) {
+ if (i != 0) exportClassPath.append(":");
+ exportClassPath.append("$JAVAROOT/" + jarList[i]);
+ }
+ } else if (exportPlatform == PConstants.WINDOWS) {
+ for (int i = 0; i < jarList.length; i++) {
+ if (i != 0) exportClassPath.append(",");
+ exportClassPath.append(jarList[i]);
+ }
+ } else {
+ for (int i = 0; i < jarList.length; i++) {
+ if (i != 0) exportClassPath.append(":");
+ exportClassPath.append("$APPDIR/lib/" + jarList[i]);
+ }
+ }
+
+
+ /// figure out run options for the VM
+
+ String runOptions = Preferences.get("run.options");
+ if (Preferences.getBoolean("run.options.memory")) {
+ runOptions += " -Xms" +
+ Preferences.get("run.options.memory.initial") + "m";
+ runOptions += " -Xmx" +
+ Preferences.get("run.options.memory.maximum") + "m";
+ }
+
+ /// macosx: write out Info.plist (template for classpath, etc)
+
+ if (exportPlatform == PConstants.MACOSX) {
+ String PLIST_TEMPLATE = "template.plist";
+ File plistTemplate = new File(folder, PLIST_TEMPLATE);
+ if (!plistTemplate.exists()) {
+ plistTemplate = new File(skeletonFolder, PLIST_TEMPLATE);
+ }
+ File plistFile = new File(dotAppFolder, "Contents/Info.plist");
+ PrintWriter pw = PApplet.createWriter(plistFile);
+
+ String lines[] = PApplet.loadStrings(plistTemplate);
+ for (int i = 0; i < lines.length; i++) {
+ if (lines[i].indexOf("@@") != -1) {
+ StringBuffer sb = new StringBuffer(lines[i]);
+ int index = 0;
+ while ((index = sb.indexOf("@@vmoptions@@")) != -1) {
+ sb.replace(index, index + "@@vmoptions@@".length(),
+ runOptions);
+ }
+ while ((index = sb.indexOf("@@sketch@@")) != -1) {
+ sb.replace(index, index + "@@sketch@@".length(),
+ name);
+ }
+ while ((index = sb.indexOf("@@classpath@@")) != -1) {
+ sb.replace(index, index + "@@classpath@@".length(),
+ exportClassPath.toString());
+ }
+ while ((index = sb.indexOf("@@lsuipresentationmode@@")) != -1) {
+ sb.replace(index, index + "@@lsuipresentationmode@@".length(),
+ Preferences.getBoolean("export.application.fullscreen") ? "4" : "0");
+ }
+ lines[i] = sb.toString();
+ }
+ // explicit newlines to avoid Windows CRLF
+ pw.print(lines[i] + "\n");
+ }
+ pw.flush();
+ pw.close();
+
+ } else if (exportPlatform == PConstants.WINDOWS) {
+ File argsFile = new File(destFolder + "/lib/args.txt");
+ PrintWriter pw = PApplet.createWriter(argsFile);
+
+ pw.println(runOptions);
+
+ pw.println(this.name);
+ pw.println(exportClassPath);
+
+ pw.flush();
+ pw.close();
+
+ } else {
+ File shellScript = new File(destFolder, this.name);
+ PrintWriter pw = PApplet.createWriter(shellScript);
+
+ // do the newlines explicitly so that windows CRLF
+ // isn't used when exporting for unix
+ pw.print("#!/bin/sh\n\n");
+ //ps.print("APPDIR=`dirname $0`\n");
+ pw.print("APPDIR=$(dirname \"$0\")\n"); // more posix compliant
+ // another fix for bug #234, LD_LIBRARY_PATH ignored on some platforms
+ //ps.print("LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$APPDIR\n");
+ pw.print("java " + Preferences.get("run.options") +
+ " -Djava.library.path=\"$APPDIR\"" +
+ " -cp \"" + exportClassPath + "\"" +
+ " " + this.name + "\n");
+
+ pw.flush();
+ pw.close();
+
+ String shellPath = shellScript.getAbsolutePath();
+ // will work on osx or *nix, but just dies on windows, oh well..
+ if (!Base.isWindows()) {
+ Runtime.getRuntime().exec(new String[] { "chmod", "+x", shellPath });
+ }
+ }
+
+
+ /// copy the source files to the target
+ /// (we like to encourage people to share their code)
+
+ File sourceFolder = new File(destFolder, "source");
+ sourceFolder.mkdirs();
+
+ for (int i = 0; i < codeCount; i++) {
+ try {
+// Base.copyFile(code[i].getFile(),
+// new File(sourceFolder, code[i].file.getFileName()));
+ code[i].copyTo(new File(sourceFolder, code[i].getFileName()));
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ // move the .java file from the preproc there too
+ String preprocFilename = this.name + ".java";
+ File preprocFile = new File(destFolder, preprocFilename);
+ if (preprocFile.exists()) {
+ preprocFile.renameTo(new File(sourceFolder, preprocFilename));
+ }
+
+
+ /// remove the .class files from the export folder.
+ for (int i = 0; i < classfiles.length; i++) {
+ if (classfiles[i].endsWith(".class")) {
+ File deadguy = new File(destFolder, classfiles[i]);
+ if (!deadguy.delete()) {
+ Base.showWarning("Could not delete",
+ classfiles[i] + " could not \n" +
+ "be deleted from the applet folder. \n" +
+ "You'll need to remove it by hand.", null);
+ }
+ }
+ }
+
+
+ /// goodbye
+ return true;
+ }
+
+
+ protected void addManifest(ZipOutputStream zos) throws IOException {
+ ZipEntry entry = new ZipEntry("META-INF/MANIFEST.MF");
+ zos.putNextEntry(entry);
+
+ String contents =
+ "Manifest-Version: 1.0\n" +
+ "Created-By: Processing " + Base.VERSION_NAME + "\n" +
+ "Main-Class: " + name + "\n"; // TODO not package friendly
+ zos.write(contents.getBytes());
+ zos.closeEntry();
+ }
+
+
+ /**
+ * Read from a file with a bunch of attribute/value pairs
+ * that are separated by = and ignore comments with #.
+ */
+ protected Hashtable readSettings(File inputFile) {
+ Hashtable outgoing = new Hashtable();
+ if (!inputFile.exists()) return outgoing; // return empty hash
+
+ String lines[] = PApplet.loadStrings(inputFile);
+ for (int i = 0; i < lines.length; i++) {
+ int hash = lines[i].indexOf('#');
+ String line = (hash == -1) ?
+ lines[i].trim() : lines[i].substring(0, hash).trim();
+ if (line.length() == 0) continue;
+
+ int equals = line.indexOf('=');
+ if (equals == -1) {
+ System.err.println("ignoring illegal line in " + inputFile);
+ System.err.println(" " + line);
+ continue;
+ }
+ String attr = line.substring(0, equals).trim();
+ String valu = line.substring(equals + 1).trim();
+ outgoing.put(attr, valu);
+ }
+ return outgoing;
+ }
+
+
+ /**
+ * Slurps up .class files from a colon (or semicolon on windows)
+ * separated list of paths and adds them to a ZipOutputStream.
+ */
+ protected void packClassPathIntoZipFile(String path,
+ ZipOutputStream zos,
+ Hashtable zipFileContents)
+ throws IOException {
+ String[] pieces = PApplet.split(path, File.pathSeparatorChar);
+
+ for (int i = 0; i < pieces.length; i++) {
+ if (pieces[i].length() == 0) continue;
+
+ // is it a jar file or directory?
+ if (pieces[i].toLowerCase().endsWith(".jar") ||
+ pieces[i].toLowerCase().endsWith(".zip")) {
+ try {
+ ZipFile file = new ZipFile(pieces[i]);
+ Enumeration entries = file.entries();
+ while (entries.hasMoreElements()) {
+ ZipEntry entry = (ZipEntry) entries.nextElement();
+ if (entry.isDirectory()) {
+ // actually 'continue's for all dir entries
+
+ } else {
+ String entryName = entry.getName();
+ // ignore contents of the META-INF folders
+ if (entryName.indexOf("META-INF") == 0) continue;
+
+ // don't allow duplicate entries
+ if (zipFileContents.get(entryName) != null) continue;
+ zipFileContents.put(entryName, new Object());
+
+ ZipEntry entree = new ZipEntry(entryName);
+
+ zos.putNextEntry(entree);
+ byte buffer[] = new byte[(int) entry.getSize()];
+ InputStream is = file.getInputStream(entry);
+
+ int offset = 0;
+ int remaining = buffer.length;
+ while (remaining > 0) {
+ int count = is.read(buffer, offset, remaining);
+ offset += count;
+ remaining -= count;
+ }
+
+ zos.write(buffer);
+ zos.flush();
+ zos.closeEntry();
+ }
+ }
+ } catch (IOException e) {
+ System.err.println("Error in file " + pieces[i]);
+ e.printStackTrace();
+ }
+ } else { // not a .jar or .zip, prolly a directory
+ File dir = new File(pieces[i]);
+ // but must be a dir, since it's one of several paths
+ // just need to check if it exists
+ if (dir.exists()) {
+ packClassPathIntoZipFileRecursive(dir, null, zos);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Continue the process of magical exporting. This function
+ * can be called recursively to walk through folders looking
+ * for more goodies that will be added to the ZipOutputStream.
+ */
+ static protected void packClassPathIntoZipFileRecursive(File dir,
+ String sofar,
+ ZipOutputStream zos)
+ throws IOException {
+ String files[] = dir.list();
+ for (int i = 0; i < files.length; i++) {
+ // ignore . .. and .DS_Store
+ if (files[i].charAt(0) == '.') continue;
+
+ File sub = new File(dir, files[i]);
+ String nowfar = (sofar == null) ?
+ files[i] : (sofar + "/" + files[i]);
+
+ if (sub.isDirectory()) {
+ packClassPathIntoZipFileRecursive(sub, nowfar, zos);
+
+ } else {
+ // don't add .jar and .zip files, since they only work
+ // inside the root, and they're unpacked
+ if (!files[i].toLowerCase().endsWith(".jar") &&
+ !files[i].toLowerCase().endsWith(".zip") &&
+ files[i].charAt(0) != '.') {
+ ZipEntry entry = new ZipEntry(nowfar);
+ zos.putNextEntry(entry);
+ zos.write(Base.loadBytesRaw(sub));
+ zos.closeEntry();
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Make sure the sketch hasn't been moved or deleted by some
+ * nefarious user. If they did, try to re-create it and save.
+ * Only checks to see if the main folder is still around,
+ * but not its contents.
+ */
+ protected void ensureExistence() {
+ if (folder.exists()) return;
+
+ Base.showWarning("Sketch Disappeared",
+ "The sketch folder has disappeared.\n " +
+ "Will attempt to re-save in the same location,\n" +
+ "but anything besides the code will be lost.", null);
+ try {
+ folder.mkdirs();
+ modified = true;
+
+ for (int i = 0; i < codeCount; i++) {
+ code[i].save(); // this will force a save
+ }
+ calcModified();
+
+ } catch (Exception e) {
+ Base.showWarning("Could not re-save sketch",
+ "Could not properly re-save the sketch. " +
+ "You may be in trouble at this point,\n" +
+ "and it might be time to copy and paste " +
+ "your code to another text editor.", e);
+ }
+ }
+
+
+ /**
+ * Returns true if this is a read-only sketch. Used for the
+ * examples directory, or when sketches are loaded from read-only
+ * volumes or folders without appropriate permissions.
+ */
+ public boolean isReadOnly() {
+ String apath = folder.getAbsolutePath();
+ if (apath.startsWith(Base.getExamplesPath()) ||
+ apath.startsWith(Base.getLibrariesPath())) {
+ return true;
+
+ // canWrite() doesn't work on directories
+ //} else if (!folder.canWrite()) {
+ } else {
+ // check to see if each modified code file can be written to
+ for (int i = 0; i < codeCount; i++) {
+ if (code[i].isModified() &&
+ code[i].fileReadOnly() &&
+ code[i].fileExists()) {
+ //System.err.println("found a read-only file " + code[i].file);
+ return true;
+ }
+ }
+ //return true;
+ }
+ return false;
+ }
+
+
+ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+
+ // Breaking out extension types in order to clean up the code, and make it
+ // easier for other environments (like Arduino) to incorporate changes.
+
+
+ /**
+ * True if the specified extension should be hidden when shown on a tab.
+ * For Processing, this is true for .pde files. (Broken out for subclasses.)
+ */
+ public boolean hideExtension(String what) {
+ return what.equals(getDefaultExtension());
+ }
+
+
+ /**
+ * True if the specified code has the default file extension.
+ */
+ public boolean hasDefaultExtension(SketchCode code) {
+ return code.getExtension().equals(getDefaultExtension());
+ }
+
+
+ /**
+ * True if the specified extension is the default file extension.
+ */
+ public boolean isDefaultExtension(String what) {
+ return what.equals(getDefaultExtension());
+ }
+
+
+ /**
+ * Check this extension (no dots, please) against the list of valid
+ * extensions.
+ */
+ public boolean validExtension(String what) {
+ String[] ext = getExtensions();
+ for (int i = 0; i < ext.length; i++) {
+ if (ext[i].equals(what)) return true;
+ }
+ return false;
+ }
+
+
+ /**
+ * Returns the default extension for this editor setup.
+ */
+ public String getDefaultExtension() {
+ return "pde";
+ }
+
+
+ /**
+ * Returns a String[] array of proper extensions.
+ */
+ public String[] getExtensions() {
+ return new String[] { "pde", "java" };
+ }
+
+
+ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+
+ // Additional accessors added in 0136 because of package work.
+ // These will also be helpful for tool developers.
+
+
+ /**
+ * Returns the name of this sketch. (The pretty name of the main tab.)
+ */
+ public String getName() {
+ return name;
+ }
+
+
+ /**
+ * Returns a file object for the primary .pde of this sketch.
+ */
+ public File getPrimaryFile() {
+ return primaryFile;
+ }
+
+
+ /**
+ * Returns path to the main .pde file for this sketch.
+ */
+ public String getMainFilePath() {
+ return primaryFile.getAbsolutePath();
+ //return code[0].file.getAbsolutePath();
+ }
+
+
+ /**
+ * Returns the sketch folder.
+ */
+ public File getFolder() {
+ return folder;
+ }
+
+
+ /**
+ * Returns the location of the sketch's data folder. (It may not exist yet.)
+ */
+ public File getDataFolder() {
+ return dataFolder;
+ }
+
+
+ /**
+ * Create the data folder if it does not exist already. As a convenience,
+ * it also returns the data folder, since it's likely about to be used.
+ */
+ public File prepareDataFolder() {
+ if (!dataFolder.exists()) {
+ dataFolder.mkdirs();
+ }
+ return dataFolder;
+ }
+
+
+ /**
+ * Returns the location of the sketch's code folder. (It may not exist yet.)
+ */
+ public File getCodeFolder() {
+ return codeFolder;
+ }
+
+
+ /**
+ * Create the code folder if it does not exist already. As a convenience,
+ * it also returns the code folder, since it's likely about to be used.
+ */
+ public File prepareCodeFolder() {
+ if (!codeFolder.exists()) {
+ codeFolder.mkdirs();
+ }
+ return codeFolder;
+ }
+
+
+ public String getClassPath() {
+ return classPath;
+ }
+
+
+ public String getLibraryPath() {
+ return libraryPath;
+ }
+
+
+ public SketchCode[] getCode() {
+ return code;
+ }
+
+
+ public int getCodeCount() {
+ return codeCount;
+ }
+
+
+ public SketchCode getCode(int index) {
+ return code[index];
+ }
+
+
+ public int getCodeIndex(SketchCode who) {
+ for (int i = 0; i < codeCount; i++) {
+ if (who == code[i]) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+
+ public SketchCode getCurrentCode() {
+ return current;
+ }
+
+
+ public void setUntitled(boolean u) {
+ editor.untitled = u;
+ }
+
+
+ public boolean isUntitled() {
+ return editor.untitled;
+ }
+
+
+ public String getAppletClassName2() {
+ return appletClassName;
+ }
+
+
+ // .................................................................
+
+
+ /**
+ * Convert to sanitized name and alert the user
+ * if changes were made.
+ */
+ static public String checkName(String origName) {
+ String newName = sanitizeName(origName);
+
+ if (!newName.equals(origName)) {
+ String msg =
+ "The sketch name had to be modified. Sketch names can only consist\n" +
+ "of ASCII characters and numbers (but cannot start with a number).\n" +
+ "They should also be less less than 64 characters long.";
+ System.out.println(msg);
+ }
+ return newName;
+ }
+
+
+ /**
+ * Return true if the name is valid for a Processing sketch.
+ */
+ static public boolean isSanitaryName(String name) {
+ return sanitizeName(name).equals(name);
+ }
+
+
+ /**
+ * Produce a sanitized name that fits our standards for likely to work.
+ *
+ * Java classes have a wider range of names that are technically allowed
+ * (supposedly any Unicode name) than what we support. The reason for
+ * going more narrow is to avoid situations with text encodings and
+ * converting during the process of moving files between operating
+ * systems, i.e. uploading from a Windows machine to a Linux server,
+ * or reading a FAT32 partition in OS X and using a thumb drive.
+ *
+ * This helper function replaces everything but A-Z, a-z, and 0-9 with
+ * underscores. Also disallows starting the sketch name with a digit.
+ */
+ static public String sanitizeName(String origName) {
+ char c[] = origName.toCharArray();
+ StringBuffer buffer = new StringBuffer();
+
+ // can't lead with a digit, so start with an underscore
+ if ((c[0] >= '0') && (c[0] <= '9')) {
+ buffer.append('_');
+ }
+ for (int i = 0; i < c.length; i++) {
+ if (((c[i] >= '0') && (c[i] <= '9')) ||
+ ((c[i] >= 'a') && (c[i] <= 'z')) ||
+ ((c[i] >= 'A') && (c[i] <= 'Z'))) {
+ buffer.append(c[i]);
+
+ } else {
+ buffer.append('_');
+ }
+ }
+ // let's not be ridiculous about the length of filenames.
+ // in fact, Mac OS 9 can handle 255 chars, though it can't really
+ // deal with filenames longer than 31 chars in the Finder.
+ // but limiting to that for sketches would mean setting the
+ // upper-bound on the character limit here to 25 characters
+ // (to handle the base name + ".class")
+ if (buffer.length() > 63) {
+ buffer.setLength(63);
+ }
+ return buffer.toString();
+ }
+}
diff --git a/app/src/processing/app/SketchCode.java b/app/src/processing/app/SketchCode.java
new file mode 100644
index 000000000..f7dae32bb
--- /dev/null
+++ b/app/src/processing/app/SketchCode.java
@@ -0,0 +1,285 @@
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+/*
+ SketchCode - data class for a single file inside a sketch
+ Part of the Processing project - http://processing.org
+
+ Copyright (c) 2004-08 Ben Fry and Casey Reas
+ Copyright (c) 2001-04 Massachusetts Institute of Technology
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+package processing.app;
+
+import java.io.*;
+
+import javax.swing.text.Document;
+import javax.swing.undo.*;
+
+
+/**
+ * Represents a single tab of a sketch.
+ */
+public class SketchCode {
+ /** Pretty name (no extension), not the full file name */
+ private String prettyName;
+
+ /** File object for where this code is located */
+ private File file;
+
+ /** Extension for this file (no dots, and in lowercase). */
+ private String extension;
+
+ /** Text of the program text for this tab */
+ private String program;
+
+ /** Document object for this tab. Currently this is a SyntaxDocument. */
+ private Document document;
+
+ /**
+ * Undo Manager for this tab, each tab keeps track of their own
+ * Editor.undo will be set to this object when this code is the tab
+ * that's currently the front.
+ */
+ private UndoManager undo = new UndoManager();
+
+ // saved positions from last time this tab was used
+ private int selectionStart;
+ private int selectionStop;
+ private int scrollPosition;
+
+ private boolean modified;
+
+ /** name of .java file after preproc */
+// private String preprocName;
+ /** where this code starts relative to the concat'd code */
+ private int preprocOffset;
+
+
+ public SketchCode(File file, String extension) {
+ this.file = file;
+ this.extension = extension;
+
+ makePrettyName();
+
+ try {
+ load();
+ } catch (IOException e) {
+ System.err.println("Error while loading code " + file.getName());
+ }
+ }
+
+
+ protected void makePrettyName() {
+ prettyName = file.getName();
+ int dot = prettyName.indexOf('.');
+ prettyName = prettyName.substring(0, dot);
+ }
+
+
+ public File getFile() {
+ return file;
+ }
+
+
+ protected boolean fileExists() {
+ return file.exists();
+ }
+
+
+ protected boolean fileReadOnly() {
+ return !file.canWrite();
+ }
+
+
+ protected boolean deleteFile() {
+ return file.delete();
+ }
+
+
+ protected boolean renameTo(File what, String ext) {
+ boolean success = file.renameTo(what);
+ if (success) {
+ this.file = what; // necessary?
+ this.extension = ext;
+ makePrettyName();
+ }
+ return success;
+ }
+
+
+ protected void copyTo(File dest) throws IOException {
+ Base.saveFile(program, dest);
+ }
+
+
+ public String getFileName() {
+ return file.getName();
+ }
+
+
+ public String getPrettyName() {
+ return prettyName;
+ }
+
+
+ public String getExtension() {
+ return extension;
+ }
+
+
+ public boolean isExtension(String what) {
+ return extension.equals(what);
+ }
+
+
+ public String getProgram() {
+ return program;
+ }
+
+
+ public void setProgram(String replacement) {
+ program = replacement;
+ }
+
+
+ public int getLineCount() {
+ return Base.countLines(program);
+ }
+
+
+ public void setModified(boolean modified) {
+ this.modified = modified;
+ }
+
+
+ public boolean isModified() {
+ return modified;
+ }
+
+
+// public void setPreprocName(String preprocName) {
+// this.preprocName = preprocName;
+// }
+//
+//
+// public String getPreprocName() {
+// return preprocName;
+// }
+
+
+ public void setPreprocOffset(int preprocOffset) {
+ this.preprocOffset = preprocOffset;
+ }
+
+
+ public int getPreprocOffset() {
+ return preprocOffset;
+ }
+
+
+ public void addPreprocOffset(int extra) {
+ preprocOffset += extra;
+ }
+
+
+ public Document getDocument() {
+ return document;
+ }
+
+
+ public void setDocument(Document d) {
+ document = d;
+ }
+
+
+ public UndoManager getUndo() {
+ return undo;
+ }
+
+
+ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+
+
+ // TODO these could probably be handled better, since it's a general state
+ // issue that's read/write from only one location in Editor (on tab switch.)
+
+
+ public int getSelectionStart() {
+ return selectionStart;
+ }
+
+
+ public int getSelectionStop() {
+ return selectionStop;
+ }
+
+
+ public int getScrollPosition() {
+ return scrollPosition;
+ }
+
+
+ protected void setState(String p, int start, int stop, int pos) {
+ program = p;
+ selectionStart = start;
+ selectionStop = stop;
+ scrollPosition = pos;
+ }
+
+
+ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+
+
+ /**
+ * Load this piece of code from a file.
+ */
+ public void load() throws IOException {
+ program = Base.loadFile(file);
+
+ if (program.indexOf('\uFFFD') != -1) {
+ System.err.println(file.getName() + " contains unrecognized characters.");
+ System.err.println("If this code was created with an older version of Processing,");
+ System.err.println("you may need to use Tools -> Fix Encoding & Reload to update");
+ System.err.println("the sketch to use UTF-8 encoding. If not, you may need to");
+ System.err.println("delete the bad characters to get rid of this warning.");
+ System.err.println();
+ }
+
+ setModified(false);
+ }
+
+
+ /**
+ * Save this piece of code, regardless of whether the modified
+ * flag is set or not.
+ */
+ public void save() throws IOException {
+ // TODO re-enable history
+ //history.record(s, SketchHistory.SAVE);
+
+ Base.saveFile(program, file);
+ setModified(false);
+ }
+
+
+ /**
+ * Save this file to another location, used by Sketch.saveAs()
+ */
+ public void saveAs(File newFile) throws IOException {
+ Base.saveFile(program, newFile);
+ }
+}
diff --git a/app/src/processing/app/Theme.java b/app/src/processing/app/Theme.java
new file mode 100644
index 000000000..b62f18828
--- /dev/null
+++ b/app/src/processing/app/Theme.java
@@ -0,0 +1,208 @@
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+/*
+ Part of the Processing project - http://processing.org
+
+ Copyright (c) 2004-06 Ben Fry and Casey Reas
+ Copyright (c) 2001-04 Massachusetts Institute of Technology
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+package processing.app;
+
+import java.awt.*;
+import java.io.*;
+import java.util.*;
+
+import processing.app.syntax.*;
+import processing.core.*;
+
+
+/**
+ * Storage class for theme settings. This was separated from the Preferences
+ * class for 1.0 so that the coloring wouldn't conflict with previous releases
+ * and to make way for future ability to customize.
+ */
+public class Theme {
+
+ /** Copy of the defaults in case the user mangles a preference. */
+ static Hashtable defaults;
+ /** Table of attributes/values for the theme. */
+ static Hashtable table = new Hashtable();;
+
+
+ static protected void init() {
+ try {
+ load(Base.getLibStream("theme/theme.txt"));
+ } catch (Exception te) {
+ Base.showError(null, "Could not read color theme settings.\n" +
+ "You'll need to reinstall Processing.", te);
+ }
+
+ // check for platform-specific properties in the defaults
+ String platformExt = "." + Base.getPlatformName();
+ 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);
+ }
+ }
+
+ // other things that have to be set explicitly for the defaults
+ setColor("run.window.bgcolor", SystemColor.control);
+
+ // clone the hash table
+ defaults = (Hashtable) table.clone();
+ }
+
+
+ static protected void load(InputStream input) throws IOException {
+ String[] lines = PApplet.loadStrings(input);
+ for (String line : lines) {
+ if ((line.length() == 0) ||
+ (line.charAt(0) == '#')) continue;
+
+ // this won't properly handle = signs being in the text
+ int equals = line.indexOf('=');
+ if (equals != -1) {
+ String key = line.substring(0, equals).trim();
+ String value = line.substring(equals + 1).trim();
+ table.put(key, value);
+ }
+ }
+ }
+
+
+ static public String get(String attribute) {
+ return (String) table.get(attribute);
+ }
+
+
+ static public String getDefault(String attribute) {
+ return (String) defaults.get(attribute);
+ }
+
+
+ static public void set(String attribute, String value) {
+ table.put(attribute, value);
+ }
+
+
+ static public boolean getBoolean(String attribute) {
+ String value = get(attribute);
+ return (new Boolean(value)).booleanValue();
+ }
+
+
+ static public void setBoolean(String attribute, boolean value) {
+ set(attribute, value ? "true" : "false");
+ }
+
+
+ static public int getInteger(String attribute) {
+ return Integer.parseInt(get(attribute));
+ }
+
+
+ static public void setInteger(String key, int value) {
+ set(key, String.valueOf(value));
+ }
+
+
+ static public Color getColor(String name) {
+ Color parsed = null;
+ String s = get(name);
+ if ((s != null) && (s.indexOf("#") == 0)) {
+ try {
+ int v = Integer.parseInt(s.substring(1), 16);
+ parsed = new Color(v);
+ } catch (Exception e) {
+ }
+ }
+ return parsed;
+ }
+
+
+ static public void setColor(String attr, Color what) {
+ String r = Integer.toHexString(what.getRed());
+ String g = Integer.toHexString(what.getGreen());
+ String b = Integer.toHexString(what.getBlue());
+ set(attr, "#" + r.substring(r.length() - 2) +
+ g.substring(g.length() - 2) + b.substring(b.length() - 2));
+ }
+
+
+ static public Font getFont(String attr) {
+ boolean replace = false;
+ String value = get(attr);
+ if (value == null) {
+ //System.out.println("reset 1");
+ value = getDefault(attr);
+ replace = true;
+ }
+
+ String[] pieces = PApplet.split(value, ',');
+ if (pieces.length != 3) {
+ value = getDefault(attr);
+ //System.out.println("reset 2 for " + attr);
+ pieces = PApplet.split(value, ',');
+ //PApplet.println(pieces);
+ replace = true;
+ }
+
+ String name = pieces[0];
+ int style = Font.PLAIN; // equals zero
+ if (pieces[1].indexOf("bold") != -1) {
+ style |= Font.BOLD;
+ }
+ if (pieces[1].indexOf("italic") != -1) {
+ style |= Font.ITALIC;
+ }
+ int size = PApplet.parseInt(pieces[2], 12);
+ Font font = new Font(name, style, size);
+
+ // replace bad font with the default
+ if (replace) {
+ //System.out.println(attr + " > " + value);
+ //setString(attr, font.getName() + ",plain," + font.getSize());
+ set(attr, value);
+ }
+
+ return font;
+ }
+
+
+ static public SyntaxStyle getStyle(String what) {
+ String str = get("editor." + what + ".style");
+
+ StringTokenizer st = new StringTokenizer(str, ",");
+
+ String s = st.nextToken();
+ if (s.indexOf("#") == 0) s = s.substring(1);
+ Color color = new Color(Integer.parseInt(s, 16));
+
+ s = st.nextToken();
+ boolean bold = (s.indexOf("bold") != -1);
+ boolean italic = (s.indexOf("italic") != -1);
+
+ return new SyntaxStyle(color, italic, bold);
+ }
+}
\ No newline at end of file
diff --git a/app/src/processing/app/UpdateCheck.java b/app/src/processing/app/UpdateCheck.java
new file mode 100644
index 000000000..28043eca4
--- /dev/null
+++ b/app/src/processing/app/UpdateCheck.java
@@ -0,0 +1,134 @@
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+/*
+ Part of the Processing project - http://processing.org
+
+ Copyright (c) 2005-06 Ben Fry and Casey Reas
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+package processing.app;
+
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.util.Random;
+
+import javax.swing.JOptionPane;
+
+import processing.core.PApplet;
+
+
+/**
+ * Threaded class to check for updates in the background.
+ *
+ * This is the class that handles the mind control and stuff for
+ * spying on our users and stealing their personal information.
+ * A random ID number is generated for each user, and hits the server
+ * to check for updates. Also included is the operating system and
+ * its version and the version of Java being used to run Processing.
+ *
+ * The ID number also helps provide us a general idea of how many
+ * people are using Processing, which helps us when writing grant
+ * proposals and that kind of thing so that we can keep Processing free.
+ */
+public class UpdateCheck implements Runnable {
+ Base base;
+ String downloadURL = "http://processing.org/download/latest.txt";
+
+ static final long ONE_DAY = 24 * 60 * 60 * 1000;
+
+
+ public UpdateCheck(Base base) {
+ Thread thread = new Thread(this);
+ thread.start();
+ }
+
+
+ public void run() {
+ //System.out.println("checking for updates...");
+
+ // generate a random id in case none exists yet
+ Random r = new Random();
+ long id = r.nextLong();
+
+ String idString = Preferences.get("update.id");
+ if (idString != null) {
+ id = Long.parseLong(idString);
+ } else {
+ Preferences.set("update.id", String.valueOf(id));
+ }
+
+ try {
+ String info;
+ info = URLEncoder.encode(id + "\t" +
+ PApplet.nf(Base.REVISION, 4) + "\t" +
+ System.getProperty("java.version") + "\t" +
+ System.getProperty("java.vendor") + "\t" +
+ System.getProperty("os.name") + "\t" +
+ System.getProperty("os.version") + "\t" +
+ System.getProperty("os.arch"), "UTF-8");
+
+ int latest = readInt(downloadURL + "?" + info);
+
+ String lastString = Preferences.get("update.last");
+ long now = System.currentTimeMillis();
+ if (lastString != null) {
+ long when = Long.parseLong(lastString);
+ if (now - when < ONE_DAY) {
+ // don't annoy the shit outta people
+ return;
+ }
+ }
+ Preferences.set("update.last", String.valueOf(now));
+
+ String prompt =
+ "A new version of Processing is available,\n" +
+ "would you like to visit the Processing download page?";
+
+ if (base.activeEditor != null) {
+ if (latest > Base.REVISION) {
+ Object[] options = { "Yes", "No" };
+ int result = JOptionPane.showOptionDialog(base.activeEditor,
+ prompt,
+ "Update",
+ JOptionPane.YES_NO_OPTION,
+ JOptionPane.QUESTION_MESSAGE,
+ null,
+ options,
+ options[0]);
+ if (result == JOptionPane.YES_OPTION) {
+ Base.openURL("http://processing.org/download/");
+ }
+ }
+ }
+ } catch (Exception e) {
+ //e.printStackTrace();
+ //System.err.println("Error while trying to check for an update.");
+ }
+ }
+
+
+ protected int readInt(String filename) throws Exception {
+ URL url = new URL(filename);
+ InputStream stream = url.openStream();
+ InputStreamReader isr = new InputStreamReader(stream);
+ BufferedReader reader = new BufferedReader(isr);
+ return Integer.parseInt(reader.readLine());
+ }
+}
diff --git a/app/src/processing/app/WebServer.java b/app/src/processing/app/WebServer.java
new file mode 100644
index 000000000..01f6cc39e
--- /dev/null
+++ b/app/src/processing/app/WebServer.java
@@ -0,0 +1,569 @@
+package processing.app;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import java.util.zip.*;
+
+//import javax.swing.SwingUtilities;
+
+/**
+ * An example of a very simple, multi-threaded HTTP server.
+ * Taken from this article on java.sun.com.
+ */
+public class WebServer implements HttpConstants {
+
+ /* Where worker threads stand idle */
+ static Vector threads = new Vector();
+
+ /* the web server's virtual root */
+ //static File root;
+
+ /* timeout on client connections */
+ static int timeout = 10000;
+
+ /* max # worker threads */
+ static int workers = 5;
+
+// static PrintStream log = System.out;
+
+
+ /*
+ static void loadProps() throws IOException {
+ File f = new File
+ (System.getProperty("java.home")+File.separator+
+ "lib"+File.separator+"www-server.properties");
+ if (f.exists()) {
+ InputStream is =new BufferedInputStream(new
+ FileInputStream(f));
+ props.load(is);
+ is.close();
+ String r = props.getProperty("root");
+ if (r != null) {
+ root = new File(r);
+ if (!root.exists()) {
+ throw new Error(root + " doesn't exist as server root");
+ }
+ }
+ r = props.getProperty("timeout");
+ if (r != null) {
+ timeout = Integer.parseInt(r);
+ }
+ r = props.getProperty("workers");
+ if (r != null) {
+ workers = Integer.parseInt(r);
+ }
+ r = props.getProperty("log");
+ if (r != null) {
+ p("opening log file: " + r);
+ log = new PrintStream(new BufferedOutputStream(
+ new FileOutputStream(r)));
+ }
+ }
+
+ // if no properties were specified, choose defaults
+ if (root == null) {
+ root = new File(System.getProperty("user.dir"));
+ }
+ if (timeout <= 1000) {
+ timeout = 5000;
+ }
+ if (workers < 25) {
+ workers = 5;
+ }
+ if (log == null) {
+ p("logging to stdout");
+ log = System.out;
+ }
+ }
+
+ static void printProps() {
+ p("root="+root);
+ p("timeout="+timeout);
+ p("workers="+workers);
+ }
+ */
+
+
+ /* print to stdout */
+// protected static void p(String s) {
+// System.out.println(s);
+// }
+
+ /* print to the log file */
+ protected static void log(String s) {
+ if (false) {
+ System.out.println(s);
+ }
+// synchronized (log) {
+// log.println(s);
+// log.flush();
+// }
+ }
+
+
+ //public static void main(String[] a) throws Exception {
+ static public int launch(String zipPath) throws IOException {
+ final ZipFile zip = new ZipFile(zipPath);
+ final HashMap entries = new HashMap();
+ Enumeration en = zip.entries();
+ while (en.hasMoreElements()) {
+ ZipEntry entry = (ZipEntry) en.nextElement();
+ entries.put(entry.getName(), entry);
+ }
+
+// if (a.length > 0) {
+// port = Integer.parseInt(a[0]);
+// }
+// loadProps();
+// printProps();
+ // start worker threads
+ for (int i = 0; i < workers; ++i) {
+ WebServerWorker w = new WebServerWorker(zip, entries);
+ Thread t = new Thread(w, "Web Server Worker #" + i);
+ t.start();
+ threads.addElement(w);
+ }
+
+ final int port = 8080;
+
+ //SwingUtilities.invokeLater(new Runnable() {
+ Runnable r = new Runnable() {
+ public void run() {
+ try {
+ ServerSocket ss = new ServerSocket(port);
+ while (true) {
+ Socket s = ss.accept();
+ WebServerWorker w = null;
+ synchronized (threads) {
+ if (threads.isEmpty()) {
+ WebServerWorker ws = new WebServerWorker(zip, entries);
+ ws.setSocket(s);
+ (new Thread(ws, "additional worker")).start();
+ } else {
+ w = (WebServerWorker) threads.elementAt(0);
+ threads.removeElementAt(0);
+ w.setSocket(s);
+ }
+ }
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ };
+ new Thread(r).start();
+// });
+ return port;
+ }
+}
+
+
+class WebServerWorker /*extends WebServer*/ implements HttpConstants, Runnable {
+ ZipFile zip;
+ HashMap entries;
+
+ final static int BUF_SIZE = 2048;
+
+ static final byte[] EOL = { (byte)'\r', (byte)'\n' };
+
+ /* buffer to use for requests */
+ byte[] buf;
+ /* Socket to client we're handling */
+ private Socket s;
+
+ WebServerWorker(ZipFile zip, HashMap entries) {
+ this.entries = entries;
+ this.zip = zip;
+
+ buf = new byte[BUF_SIZE];
+ s = null;
+ }
+
+// Worker() {
+// buf = new byte[BUF_SIZE];
+// s = null;
+// }
+//
+ synchronized void setSocket(Socket s) {
+ this.s = s;
+ notify();
+ }
+
+ public synchronized void run() {
+ while(true) {
+ if (s == null) {
+ /* nothing to do */
+ try {
+ wait();
+ } catch (InterruptedException e) {
+ /* should not happen */
+ continue;
+ }
+ }
+ try {
+ handleClient();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ /* go back in wait queue if there's fewer
+ * than numHandler connections.
+ */
+ s = null;
+ Vector pool = WebServer.threads;
+ synchronized (pool) {
+ if (pool.size() >= WebServer.workers) {
+ /* too many threads, exit this one */
+ return;
+ } else {
+ pool.addElement(this);
+ }
+ }
+ }
+ }
+
+
+ void handleClient() throws IOException {
+ InputStream is = new BufferedInputStream(s.getInputStream());
+ PrintStream ps = new PrintStream(s.getOutputStream());
+ // we will only block in read for this many milliseconds
+ // before we fail with java.io.InterruptedIOException,
+ // at which point we will abandon the connection.
+ s.setSoTimeout(WebServer.timeout);
+ s.setTcpNoDelay(true);
+ // zero out the buffer from last time
+ for (int i = 0; i < BUF_SIZE; i++) {
+ buf[i] = 0;
+ }
+ try {
+ // We only support HTTP GET/HEAD, and don't support any fancy HTTP
+ // options, so we're only interested really in the first line.
+ int nread = 0, r = 0;
+
+outerloop:
+ while (nread < BUF_SIZE) {
+ r = is.read(buf, nread, BUF_SIZE - nread);
+ if (r == -1) {
+ return; // EOF
+ }
+ int i = nread;
+ nread += r;
+ for (; i < nread; i++) {
+ if (buf[i] == (byte)'\n' || buf[i] == (byte)'\r') {
+ break outerloop; // read one line
+ }
+ }
+ }
+
+ /* are we doing a GET or just a HEAD */
+ boolean doingGet;
+ /* beginning of file name */
+ int index;
+ if (buf[0] == (byte)'G' &&
+ buf[1] == (byte)'E' &&
+ buf[2] == (byte)'T' &&
+ buf[3] == (byte)' ') {
+ doingGet = true;
+ index = 4;
+ } else if (buf[0] == (byte)'H' &&
+ buf[1] == (byte)'E' &&
+ buf[2] == (byte)'A' &&
+ buf[3] == (byte)'D' &&
+ buf[4] == (byte)' ') {
+ doingGet = false;
+ index = 5;
+ } else {
+ /* we don't support this method */
+ ps.print("HTTP/1.0 " + HTTP_BAD_METHOD +
+ " unsupported method type: ");
+ ps.write(buf, 0, 5);
+ ps.write(EOL);
+ ps.flush();
+ s.close();
+ return;
+ }
+
+ int i = 0;
+ /* find the file name, from:
+ * GET /foo/bar.html HTTP/1.0
+ * extract "/foo/bar.html"
+ */
+ for (i = index; i < nread; i++) {
+ if (buf[i] == (byte)' ') {
+ break;
+ }
+ }
+
+ String fname = new String(buf, index, i-index);
+ // get the zip entry, remove the front slash
+ ZipEntry entry = entries.get(fname.substring(1));
+ //System.out.println(fname + " " + entry);
+ boolean ok = printHeaders(entry, ps);
+ if (entry != null) {
+ InputStream stream = zip.getInputStream(entry);
+ if (doingGet && ok) {
+ sendFile(stream, ps);
+ }
+ } else {
+ send404(ps);
+ }
+ /*
+ String fname =
+ (new String(buf, 0, index, i-index)).replace('/', File.separatorChar);
+ if (fname.startsWith(File.separator)) {
+ fname = fname.substring(1);
+ }
+ File targ = new File(WebServer.root, fname);
+ if (targ.isDirectory()) {
+ File ind = new File(targ, "index.html");
+ if (ind.exists()) {
+ targ = ind;
+ }
+ }
+ boolean OK = printHeaders(targ, ps);
+ if (doingGet) {
+ if (OK) {
+ sendFile(targ, ps);
+ } else {
+ send404(targ, ps);
+ }
+ }
+ */
+ } finally {
+ s.close();
+ }
+ }
+
+
+ boolean printHeaders(ZipEntry targ, PrintStream ps) throws IOException {
+ boolean ret = false;
+ int rCode = 0;
+ if (targ == null) {
+ rCode = HTTP_NOT_FOUND;
+ ps.print("HTTP/1.0 " + HTTP_NOT_FOUND + " Not Found");
+ ps.write(EOL);
+ ret = false;
+ } else {
+ rCode = HTTP_OK;
+ ps.print("HTTP/1.0 " + HTTP_OK + " OK");
+ ps.write(EOL);
+ ret = true;
+ }
+ if (targ != null) {
+ WebServer.log("From " +s.getInetAddress().getHostAddress()+": GET " + targ.getName()+" --> "+rCode);
+ }
+ ps.print("Server: Processing Documentation Server");
+ ps.write(EOL);
+ ps.print("Date: " + (new Date()));
+ ps.write(EOL);
+ if (ret) {
+ if (!targ.isDirectory()) {
+ ps.print("Content-length: " + targ.getSize());
+ ps.write(EOL);
+ ps.print("Last Modified: " + new Date(targ.getTime()));
+ ps.write(EOL);
+ String name = targ.getName();
+ int ind = name.lastIndexOf('.');
+ String ct = null;
+ if (ind > 0) {
+ ct = (String) map.get(name.substring(ind));
+ }
+ if (ct == null) {
+ //System.err.println("unknown content type " + name.substring(ind));
+ ct = "application/x-unknown-content-type";
+ }
+ ps.print("Content-type: " + ct);
+ ps.write(EOL);
+ } else {
+ ps.print("Content-type: text/html");
+ ps.write(EOL);
+ }
+ }
+ ps.write(EOL); // adding another newline here [fry]
+ return ret;
+ }
+
+
+ boolean printHeaders(File targ, PrintStream ps) throws IOException {
+ boolean ret = false;
+ int rCode = 0;
+ if (!targ.exists()) {
+ rCode = HTTP_NOT_FOUND;
+ ps.print("HTTP/1.0 " + HTTP_NOT_FOUND + " Not Found");
+ ps.write(EOL);
+ ret = false;
+ } else {
+ rCode = HTTP_OK;
+ ps.print("HTTP/1.0 " + HTTP_OK+" OK");
+ ps.write(EOL);
+ ret = true;
+ }
+ WebServer.log("From " +s.getInetAddress().getHostAddress()+": GET " + targ.getAbsolutePath()+"-->"+rCode);
+ ps.print("Server: Simple java");
+ ps.write(EOL);
+ ps.print("Date: " + (new Date()));
+ ps.write(EOL);
+ if (ret) {
+ if (!targ.isDirectory()) {
+ ps.print("Content-length: " + targ.length());
+ ps.write(EOL);
+ ps.print("Last Modified: " + new Date(targ.lastModified()));
+ ps.write(EOL);
+ String name = targ.getName();
+ int ind = name.lastIndexOf('.');
+ String ct = null;
+ if (ind > 0) {
+ ct = (String) map.get(name.substring(ind));
+ }
+ if (ct == null) {
+ ct = "unknown/unknown";
+ }
+ ps.print("Content-type: " + ct);
+ ps.write(EOL);
+ } else {
+ ps.print("Content-type: text/html");
+ ps.write(EOL);
+ }
+ }
+ return ret;
+ }
+
+
+ void send404(PrintStream ps) throws IOException {
+ ps.write(EOL);
+ ps.write(EOL);
+ ps.print("
\n");
+ ps.println("Parent Directory \n");
+ String[] list = dir.list();
+ for (int i = 0; list != null && i < list.length; i++) {
+ File f = new File(dir, list[i]);
+ if (f.isDirectory()) {
+ ps.println(""+list[i]+"/ ");
+ } else {
+ ps.println(""+list[i]+"
" + (new Date()) + "");
+ }
+
+}
+
+
+interface HttpConstants {
+ /** 2XX: generally "OK" */
+ public static final int HTTP_OK = 200;
+ public static final int HTTP_CREATED = 201;
+ public static final int HTTP_ACCEPTED = 202;
+ public static final int HTTP_NOT_AUTHORITATIVE = 203;
+ public static final int HTTP_NO_CONTENT = 204;
+ public static final int HTTP_RESET = 205;
+ public static final int HTTP_PARTIAL = 206;
+
+ /** 3XX: relocation/redirect */
+ public static final int HTTP_MULT_CHOICE = 300;
+ public static final int HTTP_MOVED_PERM = 301;
+ public static final int HTTP_MOVED_TEMP = 302;
+ public static final int HTTP_SEE_OTHER = 303;
+ public static final int HTTP_NOT_MODIFIED = 304;
+ public static final int HTTP_USE_PROXY = 305;
+
+ /** 4XX: client error */
+ public static final int HTTP_BAD_REQUEST = 400;
+ public static final int HTTP_UNAUTHORIZED = 401;
+ public static final int HTTP_PAYMENT_REQUIRED = 402;
+ public static final int HTTP_FORBIDDEN = 403;
+ public static final int HTTP_NOT_FOUND = 404;
+ public static final int HTTP_BAD_METHOD = 405;
+ public static final int HTTP_NOT_ACCEPTABLE = 406;
+ public static final int HTTP_PROXY_AUTH = 407;
+ public static final int HTTP_CLIENT_TIMEOUT = 408;
+ public static final int HTTP_CONFLICT = 409;
+ public static final int HTTP_GONE = 410;
+ public static final int HTTP_LENGTH_REQUIRED = 411;
+ public static final int HTTP_PRECON_FAILED = 412;
+ public static final int HTTP_ENTITY_TOO_LARGE = 413;
+ public static final int HTTP_REQ_TOO_LONG = 414;
+ public static final int HTTP_UNSUPPORTED_TYPE = 415;
+
+ /** 5XX: server error */
+ public static final int HTTP_SERVER_ERROR = 500;
+ public static final int HTTP_INTERNAL_ERROR = 501;
+ public static final int HTTP_BAD_GATEWAY = 502;
+ public static final int HTTP_UNAVAILABLE = 503;
+ public static final int HTTP_GATEWAY_TIMEOUT = 504;
+ public static final int HTTP_VERSION = 505;
+}
diff --git a/app/src/processing/app/debug/Compiler.java b/app/src/processing/app/debug/Compiler.java
new file mode 100644
index 000000000..3eead5c42
--- /dev/null
+++ b/app/src/processing/app/debug/Compiler.java
@@ -0,0 +1,828 @@
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+/*
+ Part of the Processing project - http://processing.org
+
+ Copyright (c) 2004-08 Ben Fry and Casey Reas
+ Copyright (c) 2001-04 Massachusetts Institute of Technology
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+package processing.app.debug;
+
+import processing.app.Base;
+import processing.app.Sketch;
+import processing.app.SketchCode;
+import processing.core.*;
+
+import java.io.*;
+import java.util.*;
+import java.util.zip.*;
+
+import org.eclipse.jdt.core.compiler.batch.BatchCompiler;
+import org.eclipse.jdt.core.compiler.CompilationProgress;
+
+
+public class Compiler {
+
+ public Compiler() { }
+
+ /**
+ * Compile with ECJ.
+ *
+ * @param sketch Sketch object to be compiled.
+ * @param buildPath Where the temporary files live and will be built from.
+ * @return true if successful.
+ * @throws RunnerException Only if there's a problem. Only then.
+ */
+ public boolean compile(Sketch sketch,
+ String buildPath,
+ String primaryClassName) throws RunnerException {
+ // This will be filled in if anyone gets angry
+ RunnerException exception = null;
+ boolean success = false;
+
+ String baseCommand[] = new String[] {
+ "-Xemacs",
+ //"-noExit", // not necessary for ecj
+ "-source", "1.5",
+ "-target", "1.5",
+ "-classpath", sketch.getClassPath(),
+ "-nowarn", // we're not currently interested in warnings (works in ecj)
+ "-d", buildPath // output the classes in the buildPath
+ };
+ //PApplet.println(baseCommand);
+
+ // make list of code files that need to be compiled
+ // (some files are skipped if they contain no class)
+ String[] sourceFiles = new String[sketch.getCodeCount()];
+ int sourceCount = 0;
+ sourceFiles[sourceCount++] =
+ new File(buildPath, primaryClassName + ".java").getAbsolutePath();
+
+ for (SketchCode code : sketch.getCode()) {
+ if (code.isExtension("java")) {
+ String path = new File(buildPath, code.getFileName()).getAbsolutePath();
+ sourceFiles[sourceCount++] = path;
+ }
+ }
+ String[] command = new String[baseCommand.length + sourceCount];
+ System.arraycopy(baseCommand, 0, command, 0, baseCommand.length);
+ // append each of the files to the command string
+ System.arraycopy(sourceFiles, 0, command, baseCommand.length, sourceCount);
+
+ //PApplet.println(command);
+
+ try {
+ // Load errors into a local StringBuffer
+ final StringBuffer errorBuffer = new StringBuffer();
+
+ // Create single method dummy writer class to slurp errors from javac
+ Writer internalWriter = new Writer() {
+ public void write(char[] buf, int off, int len) {
+ errorBuffer.append(buf, off, len);
+ }
+
+ public void flush() { }
+
+ public void close() { }
+ };
+ // Wrap as a PrintWriter since that's what compile() wants
+ PrintWriter writer = new PrintWriter(internalWriter);
+
+ //result = com.sun.tools.javac.Main.compile(command, writer);
+
+ CompilationProgress progress = null;
+ PrintWriter outWriter = new PrintWriter(System.out);
+ success = BatchCompiler.compile(command, outWriter, writer, progress);
+ // Close out the stream for good measure
+ writer.flush();
+ writer.close();
+
+ BufferedReader reader =
+ new BufferedReader(new StringReader(errorBuffer.toString()));
+ //System.err.println(errorBuffer.toString());
+
+ String line = null;
+ while ((line = reader.readLine()) != null) {
+ //System.out.println("got line " + line); // debug
+
+ // get first line, which contains file name, line number,
+ // and at least the first line of the error message
+ String errorFormat = "([\\w\\d_]+.java):(\\d+):\\s*(.*):\\s*(.*)\\s*";
+ String[] pieces = PApplet.match(line, errorFormat);
+ //PApplet.println(pieces);
+
+ // if it's something unexpected, die and print the mess to the console
+ if (pieces == null) {
+ exception = new RunnerException("Cannot parse error text: " + line);
+ exception.hideStackTrace();
+ // Send out the rest of the error message to the console.
+ System.err.println(line);
+ while ((line = reader.readLine()) != null) {
+ System.err.println(line);
+ }
+ break;
+ }
+
+ // translate the java filename and line number into a un-preprocessed
+ // location inside a source file or tab in the environment.
+ String dotJavaFilename = pieces[1];
+ // Line numbers are 1-indexed from javac
+ int dotJavaLineIndex = PApplet.parseInt(pieces[2]) - 1;
+ String errorMessage = pieces[4];
+
+ int codeIndex = 0; //-1;
+ int codeLine = -1;
+
+ // first check to see if it's a .java file
+ for (int i = 0; i < sketch.getCodeCount(); i++) {
+ SketchCode code = sketch.getCode(i);
+ if (code.isExtension("java")) {
+ if (dotJavaFilename.equals(code.getFileName())) {
+ codeIndex = i;
+ codeLine = dotJavaLineIndex;
+ }
+ }
+ }
+
+ // if it's not a .java file, codeIndex will still be 0
+ if (codeIndex == 0) { // main class, figure out which tab
+ //for (int i = 1; i < sketch.getCodeCount(); i++) {
+ for (int i = 0; i < sketch.getCodeCount(); i++) {
+ SketchCode code = sketch.getCode(i);
+
+ if (code.isExtension("pde")) {
+ if (code.getPreprocOffset() <= dotJavaLineIndex) {
+ codeIndex = i;
+ //System.out.println("i'm thinkin file " + i);
+ codeLine = dotJavaLineIndex - code.getPreprocOffset();
+ }
+ }
+ }
+
+ //if (codeLine != -1) {
+ //codeLine = dotJavaLineIndex - sketch.getCode(codeIndex).getPreprocOffset();
+ //}
+ }
+ //System.out.println("code line now " + codeLine);
+ exception = new RunnerException(errorMessage, codeIndex, codeLine, -1, false);
+
+ // for a test case once message parsing is implemented,
+ // use new Font(...) since that wasn't getting picked up properly.
+
+ /*
+ if (errorMessage.equals("cannot find symbol")) {
+ handleCannotFindSymbol(reader, exception);
+
+ } else if (errorMessage.indexOf("is already defined") != -1) {
+ reader.readLine(); // repeats the line of code w/ error
+ int codeColumn = caretColumn(reader.readLine());
+ exception = new RunnerException(errorMessage,
+ codeIndex, codeLine, codeColumn);
+
+ } else if (errorMessage.startsWith("package") &&
+ errorMessage.endsWith("does not exist")) {
+ // Because imports are stripped out and re-added to the 0th line of
+ // the preprocessed code, codeLine will always be wrong for imports.
+ exception = new RunnerException("P" + errorMessage.substring(1) +
+ ". You might be missing a library.");
+ } else {
+ exception = new RunnerException(errorMessage);
+ }
+ */
+ if (errorMessage.startsWith("The import ") &&
+ errorMessage.endsWith("cannot be resolved")) {
+ // The import poo cannot be resolved
+ //import poo.shoe.blah.*;
+ String what = errorMessage.substring("The import ".length());
+ what = what.substring(0, what.indexOf(' '));
+ System.err.println("Note that release 1.0, libraries must be " +
+ "installed in a folder named 'libraries' " +
+ "inside the 'sketchbook' folder.");
+ exception.setMessage("The package " +
+ "\u201C" + what + "\u201D" +
+ " does not exist. " +
+ "You might be missing a library.");
+
+ // Actually create the folder and open it for the user
+ File sketchbookLibraries = Base.getSketchbookLibrariesFolder();
+ if (!sketchbookLibraries.exists()) {
+ if (sketchbookLibraries.mkdirs()) {
+ Base.openFolder(sketchbookLibraries);
+ }
+ }
+
+ } else if (errorMessage.endsWith("cannot be resolved to a type")) {
+ // xxx cannot be resolved to a type
+ //xxx c;
+
+ String what = errorMessage.substring(0, errorMessage.indexOf(' '));
+
+ if (what.equals("BFont") ||
+ what.equals("BGraphics") ||
+ what.equals("BImage")) {
+ handleCrustyCode(exception);
+
+ } else {
+ exception.setMessage("Cannot find a class or type " +
+ "named \u201C" + what + "\u201D");
+ }
+
+ } else if (errorMessage.endsWith("cannot be resolved")) {
+ // xxx cannot be resolved
+ //println(xxx);
+
+ String what = errorMessage.substring(0, errorMessage.indexOf(' '));
+
+ if (what.equals("LINE_LOOP") ||
+ what.equals("LINE_STRIP") ||
+ what.equals("framerate")) {
+ handleCrustyCode(exception);
+
+ } else {
+ exception.setMessage("Cannot find anything " +
+ "named \u201C" + what + "\u201D");
+ }
+
+ } else if (errorMessage.startsWith("Duplicate")) {
+ // "Duplicate nested type xxx"
+ // "Duplicate local variable xxx"
+
+ } else {
+ String[] parts = null;
+
+ // The method xxx(String) is undefined for the type Temporary_XXXX_XXXX
+ //xxx("blah");
+ // The method xxx(String, int) is undefined for the type Temporary_XXXX_XXXX
+ //xxx("blah", 34);
+ // The method xxx(String, int) is undefined for the type PApplet
+ //PApplet.sub("ding");
+ String undefined =
+ "The method (\\S+\\(.*\\)) is undefined for the type (.*)";
+ parts = PApplet.match(errorMessage, undefined);
+ if (parts != null) {
+ if (parts[1].equals("framerate(int)") ||
+ parts[1].equals("push()")) {
+ handleCrustyCode(exception);
+ } else {
+ String mess = "The function " + parts[1] + " does not exist.";
+ exception.setMessage(mess);
+ }
+ break;
+ }
+ }
+ if (exception != null) {
+ // The stack trace just shows that this happened inside the compiler,
+ // which is a red herring. Don't ever show it for compiler stuff.
+ exception.hideStackTrace();
+ break;
+ }
+ }
+ } catch (IOException e) {
+ String bigSigh = "Error while compiling. (" + e.getMessage() + ")";
+ exception = new RunnerException(bigSigh);
+ e.printStackTrace();
+ success = false;
+ }
+ // In case there was something else.
+ if (exception != null) throw exception;
+
+ return success;
+ }
+
+
+ /**
+ * Fire up 'ole javac based on this interface.
+ *
+ * @param sketch Sketch object to be compiled.
+ * @param buildPath Where the temporary files live and will be built from.
+ * @return
+ * @throws RunnerException Only if there's a problem. Only then.
+ */
+// public boolean compileJavac(Sketch sketch,
+// String buildPath) throws RunnerException {
+// // This will be filled in if anyone gets angry
+// RunnerException exception = null;
+//
+// String baseCommand[] = new String[] {
+// "-source", "1.5",
+// "-target", "1.5",
+// "-classpath", sketch.getClassPath(),
+// "-nowarn", // we're not currently interested in warnings (ignored?)
+// "-d", buildPath // output the classes in the buildPath
+// };
+// //PApplet.println(baseCommand);
+//
+// // make list of code files that need to be compiled
+// // (some files are skipped if they contain no class)
+// String[] preprocNames = new String[sketch.getCodeCount()];
+// int preprocCount = 0;
+// for (int i = 0; i < sketch.getCodeCount(); i++) {
+// if (sketch.getCode(i).preprocName != null) {
+// preprocNames[preprocCount++] = sketch.getCode(i).preprocName;
+// }
+// }
+// String[] command = new String[baseCommand.length + preprocCount];
+// System.arraycopy(baseCommand, 0, command, 0, baseCommand.length);
+// // append each of the files to the command string
+// for (int i = 0; i < preprocCount; i++) {
+// command[baseCommand.length + i] =
+// buildPath + File.separator + preprocNames[i];
+// }
+// //PApplet.println(command);
+//
+// int result = -1; // needs to be set bad by default, in case hits IOE below
+//
+// try {
+// // Load errors into a local StringBuffer
+// final StringBuffer errorBuffer = new StringBuffer();
+//
+// // Create single method dummy writer class to slurp errors from javac
+// Writer internalWriter = new Writer() {
+// public void write(char[] buf, int off, int len) {
+// errorBuffer.append(buf, off, len);
+// }
+//
+// public void flush() { }
+//
+// public void close() { }
+// };
+// // Wrap as a PrintWriter since that's what compile() wants
+// PrintWriter writer = new PrintWriter(internalWriter);
+//
+// result = com.sun.tools.javac.Main.compile(command, writer);
+//
+// // Close out the stream for good measure
+// writer.flush();
+// writer.close();
+//
+//// BufferedReader reader =
+//// new BufferedReader(new StringReader(errorBuffer.toString()));
+// //System.err.println(errorBuffer.toString());
+//
+//// String m = errorBuffer.toString();
+// //ParsePosition mp = new ParsePosition(0);
+//
+//// while (mp.getIndex() < m.length()) { // reading messages
+// String line = null;
+// int lineIndex = 0;
+// String[] lines = PApplet.split(errorBuffer.toString(), '\n');
+// int lineCount = lines.length;
+// while (lineIndex < lineCount) {
+// //while ((line = reader.readLine()) != null) {
+// //System.out.println("got line " + line); // debug
+//
+// /*
+//compiler.misc.count.error=\
+// {0} error
+//compiler.misc.count.error.plural=\
+// {0} errors
+//compiler.misc.count.warn=\
+// {0} warning
+//compiler.misc.count.warn.plural=\
+// {0} warnings
+// */
+// // Check to see if this is the last line.
+//// if ((PApplet.match(line, "\\d+ error[s]?") != null) ||
+//// (PApplet.match(line, "\\d+ warning[s]?") != null)) {
+//// break;
+//// }
+// if (isCompilerMatch(line, "compiler.misc.count.error") ||
+// isCompilerMatch(line, "compiler.misc.count.error.plural") ||
+// isCompilerMatch(line, "compiler.misc.count.warn") ||
+// isCompilerMatch(line, "compiler.misc.count.warn.plural")) {
+// break;
+// }
+//
+// // Hide these because people are getting confused
+// // http://dev.processing.org/bugs/show_bug.cgi?id=817
+// // com/sun/tools/javac/resources/compiler.properties
+// //if (line.startsWith("Note: ")) {
+// String compilerNote = compilerResources.getString("compiler.note.note");
+// MessageFormat noteFormat = new MessageFormat(compilerNote + " {0}");
+// Object[] noteFound;
+// try {
+// noteFound = noteFormat.parse(line);
+// if (noteFound != null) {
+// System.out.println("gefunden " + noteFound[0]);
+//
+// /*
+// // if you mention serialVersionUID one more time, i'm kickin' you out
+// if (line.indexOf("serialVersionUID") != -1) continue;
+// // {0} uses unchecked or unsafe operations.
+// // Some input files use unchecked or unsafe operations.
+// if (line.indexOf("or unsafe operations") != -1) continue;
+// // {0} uses or overrides a deprecated API.
+// // Some input files use or override a deprecated API.
+// if (line.indexOf("or override") != -1) continue;
+// // Recompile with -Xlint:deprecation for details.
+// // Recompile with -Xlint:unchecked for details.
+// if (line.indexOf("Recompile with -Xlint:") != -1) continue;
+// System.err.println(line);
+// */
+// continue;
+// }
+// } catch (ParseException e) {
+// e.printStackTrace();
+// }
+//
+// // get first line, which contains file name, line number,
+// // and at least the first line of the error message
+// String errorFormat = "([\\w\\d_]+.java):(\\d+):\\s*(.*)\\s*";
+// String[] pieces = PApplet.match(line, errorFormat);
+//
+// // if it's something unexpected, die and print the mess to the console
+// if (pieces == null) {
+// exception = new RunnerException("Cannot parse error text: " + line);
+// exception.hideStackTrace();
+// // Send out the rest of the error message to the console.
+// System.err.println(line);
+// //while ((line = reader.readLine()) != null) {
+// for (int i = lineIndex; i < lineCount; i++) {
+// System.err.println(lines[i]);
+// }
+// break;
+// }
+//
+// // translate the java filename and line number into a un-preprocessed
+// // location inside a source file or tab in the environment.
+// String dotJavaFilename = pieces[0];
+// // Line numbers are 1-indexed from javac
+// int dotJavaLineIndex = PApplet.parseInt(pieces[1]) - 1;
+// String errorMessage = pieces[2];
+//
+// int codeIndex = -1;
+// int codeLine = -1;
+// for (int i = 0; i < sketch.getCodeCount(); i++) {
+// String name = sketch.getCode(i).preprocName;
+// if ((name != null) && dotJavaFilename.equals(name)) {
+// codeIndex = i;
+// }
+// }
+// //System.out.println("code index/line are " + codeIndex + " " + codeLine);
+// //System.out.println("java line number " + dotJavaLineIndex + " from " + dotJavaFilename);
+//
+// if (codeIndex == 0) { // main class, figure out which tab
+// for (int i = 1; i < sketch.getCodeCount(); i++) {
+// SketchCode code = sketch.getCode(i);
+//
+// if (code.flavor == Sketch.PDE) {
+// if (code.preprocOffset <= dotJavaLineIndex) {
+// codeIndex = i;
+// //System.out.println("i'm thinkin file " + i);
+// }
+// }
+// }
+// }
+// //System.out.println("preproc offset is " + sketch.getCode(codeIndex).preprocOffset);
+// codeLine = dotJavaLineIndex - sketch.getCode(codeIndex).preprocOffset;
+// //System.out.println("code line now " + codeLine);
+// exception = new RunnerException(errorMessage, codeIndex, codeLine, -1, false);
+//
+// // for a test case once message parsing is implemented,
+// // use new Font(...) since that wasn't getting picked up properly.
+//
+// if (errorMessage.equals("cannot find symbol")) {
+// handleCannotFindSymbol(reader, exception);
+//
+// } else if (errorMessage.indexOf("is already defined") != -1) {
+// reader.readLine(); // repeats the line of code w/ error
+// int codeColumn = caretColumn(reader.readLine());
+// exception = new RunnerException(errorMessage,
+// codeIndex, codeLine, codeColumn);
+//
+// } else if (errorMessage.startsWith("package") &&
+// errorMessage.endsWith("does not exist")) {
+// // Because imports are stripped out and re-added to the 0th line of
+// // the preprocessed code, codeLine will always be wrong for imports.
+// exception = new RunnerException("P" + errorMessage.substring(1) +
+// ". You might be missing a library.");
+// } else {
+// exception = new RunnerException(errorMessage);
+// }
+// if (exception != null) {
+// // The stack trace just shows that this happened inside the compiler,
+// // which is a red herring. Don't ever show it for compiler stuff.
+// exception.hideStackTrace();
+// break;
+// }
+// }
+// } catch (IOException e) {
+// String bigSigh = "Error while compiling. (" + e.getMessage() + ")";
+// exception = new RunnerException(bigSigh);
+// e.printStackTrace();
+// result = 1;
+// }
+// // In case there was something else.
+// if (exception != null) throw exception;
+//
+// // Success means that 'result' is set to zero
+// return (result == 0);
+// }
+//
+//
+// boolean isCompilerMatch(String line, String format) {
+// return compilerMatch(line, format) != null;
+// }
+//
+//
+// Object[] compilerMatch(String line, String name) {
+// String format = compilerResources.getString(name);
+// MessageFormat mf = new MessageFormat(format);
+// Object[] matches = null;
+// try {
+// matches = mf.parse(line);
+// } catch (ParseException e) {
+// e.printStackTrace();
+// }
+// return matches;
+// }
+
+
+// boolean isCompilerMatch(String line, ParsePosition pos, String format) {
+// return compilerMatch(line, pos, format) != null;
+// }
+//
+//
+// Object[] compilerMatch(String line, ParsePosition pos, String name) {
+// String format = compilerResources.getString(name);
+// MessageFormat mf = new MessageFormat(format);
+// Object[] matches = mf.parse(line, pos);
+// return matches;
+// }
+
+
+ // Tell-tale signs of old code copied and pasted from the web.
+ // Detect classes BFont, BGraphics, BImage; methods framerate, push;
+ // and variables LINE_LOOP and LINE_STRIP.
+// static HashMap crusties = new HashMap();
+// static {
+// crusties.put("BFont", new Object());
+// crusties.put("BGraphics", new Object());
+// crusties.put("BImage", new Object());
+// crusties.put("framerate", new Object());
+// crusties.put("push", new Object());
+// crusties.put("LINE_LOOP", new Object());
+// crusties.put("LINE_STRIP", new Object());
+// }
+
+
+// void handleCannotFindSymbol(BufferedReader reader,
+// RunnerException rex) throws IOException {
+// String symbolLine = reader.readLine();
+// String locationLine = reader.readLine();
+// /*String codeLine =*/ reader.readLine();
+// String caretLine = reader.readLine();
+// rex.setCodeColumn(caretColumn(caretLine));
+//
+// String[] pieces =
+// PApplet.match(symbolLine, "symbol\\s*:\\s*(\\w+)\\s+(.*)");
+// if (pieces != null) {
+// if (pieces[0].equals("class") ||
+// pieces[0].equals("variable")) {
+// rex.setMessage("Cannot find a " + pieces[0] + " " +
+// "named \u201C" + pieces[1] + "\u201D");
+// if (crusties.get(pieces[1]) != null) {
+// handleCrustyCode(rex);
+// }
+//
+// } else if (pieces[0].equals("method")) {
+// int leftParen = pieces[1].indexOf("(");
+// int rightParen = pieces[1].indexOf(")");
+//
+// String methodName = pieces[1].substring(0, leftParen);
+// String methodParams = pieces[1].substring(leftParen + 1, rightParen);
+//
+// String message =
+// "Cannot find a function named \u201C" + methodName + "\u201D";
+// if (methodParams.length() > 0) {
+// if (methodParams.indexOf(',') != -1) {
+// message += " with parameters ";
+// } else {
+// message += " with parameter ";
+// }
+// message += methodParams;
+// }
+//
+// String locationClass = "location: class ";
+// if (locationLine.startsWith(locationClass) &&
+// // don't include the class name when it's a temp class
+// locationLine.indexOf("Temporary_") == -1) {
+// String className = locationLine.substring(locationClass.length());
+// // If no dot exists, -1 + 1 is 0, so this will have no effect.
+// className = className.substring(className.lastIndexOf('.') + 1);
+// int bracket = className.indexOf('[');
+// if (bracket == -1) {
+// message += " in class " + className;
+// } else {
+// className = className.substring(0, bracket);
+// message += " for an array of " + className + " objects";
+// }
+// }
+// message += ".";
+// rex.setMessage(message);
+//
+// // On second thought, make sure this isn't just some alpha/beta code
+// if (crusties.get(methodName) != null) {
+// handleCrustyCode(rex);
+// }
+//
+// } else {
+// System.out.println(symbolLine);
+// }
+// }
+// }
+
+
+ void handleCrustyCode(RunnerException rex) {
+ rex.setMessage("This code needs to be updated, " +
+ "please read the \u201Cchanges\u201D reference.");
+ Base.showReference("changes.html");
+ }
+
+
+ protected int caretColumn(String caretLine) {
+ return caretLine.indexOf("^");
+ }
+
+
+ /////////////////////////////////////////////////////////////////////////////
+
+
+ /**
+ * Given a folder, return a list of absolute paths to all jar or zip files
+ * inside that folder, separated by pathSeparatorChar.
+ *
+ * This will prepend a colon (or whatever the path separator is)
+ * so that it can be directly appended to another path string.
+ *
+ * As of 0136, this will no longer add the root folder as well.
+ *
+ * This function doesn't bother checking to see if there are any .class
+ * files in the folder or within a subfolder.
+ */
+ static public String contentsToClassPath(File folder) {
+ if (folder == null) return "";
+
+ StringBuffer abuffer = new StringBuffer();
+ String sep = System.getProperty("path.separator");
+
+ try {
+ String path = folder.getCanonicalPath();
+
+// disabled as of 0136
+ // add the folder itself in case any unzipped files
+// abuffer.append(sep);
+// abuffer.append(path);
+//
+ // When getting the name of this folder, make sure it has a slash
+ // after it, so that the names of sub-items can be added.
+ if (!path.endsWith(File.separator)) {
+ path += File.separator;
+ }
+
+ String list[] = folder.list();
+ for (int i = 0; i < list.length; i++) {
+ // Skip . and ._ files. Prior to 0125p3, .jar files that had
+ // OS X AppleDouble files associated would cause trouble.
+ if (list[i].startsWith(".")) continue;
+
+ if (list[i].toLowerCase().endsWith(".jar") ||
+ list[i].toLowerCase().endsWith(".zip")) {
+ abuffer.append(sep);
+ abuffer.append(path);
+ abuffer.append(list[i]);
+ }
+ }
+ } catch (IOException e) {
+ e.printStackTrace(); // this would be odd
+ }
+ //System.out.println("included path is " + abuffer.toString());
+ //packageListFromClassPath(abuffer.toString()); // WHY?
+ return abuffer.toString();
+ }
+
+
+ /**
+ * A classpath, separated by the path separator, will contain
+ * a series of .jar/.zip files or directories containing .class
+ * files, or containing subdirectories that have .class files.
+ *
+ * @param path the input classpath
+ * @return array of possible package names
+ */
+ static public String[] packageListFromClassPath(String path) {
+ Hashtable table = new Hashtable();
+ String pieces[] =
+ PApplet.split(path, File.pathSeparatorChar);
+
+ for (int i = 0; i < pieces.length; i++) {
+ //System.out.println("checking piece '" + pieces[i] + "'");
+ if (pieces[i].length() == 0) continue;
+
+ if (pieces[i].toLowerCase().endsWith(".jar") ||
+ pieces[i].toLowerCase().endsWith(".zip")) {
+ //System.out.println("checking " + pieces[i]);
+ packageListFromZip(pieces[i], table);
+
+ } else { // it's another type of file or directory
+ File dir = new File(pieces[i]);
+ if (dir.exists() && dir.isDirectory()) {
+ packageListFromFolder(dir, null, table);
+ //importCount = magicImportsRecursive(dir, null,
+ // table);
+ //imports, importCount);
+ }
+ }
+ }
+ int tableCount = table.size();
+ String output[] = new String[tableCount];
+ int index = 0;
+ Enumeration e = table.keys();
+ while (e.hasMoreElements()) {
+ output[index++] = ((String) e.nextElement()).replace('/', '.');
+ }
+ //System.arraycopy(imports, 0, output, 0, importCount);
+ //PApplet.printarr(output);
+ return output;
+ }
+
+
+ static private void packageListFromZip(String filename, Hashtable table) {
+ try {
+ ZipFile file = new ZipFile(filename);
+ Enumeration entries = file.entries();
+ while (entries.hasMoreElements()) {
+ ZipEntry entry = (ZipEntry) entries.nextElement();
+
+ if (!entry.isDirectory()) {
+ String name = entry.getName();
+
+ if (name.endsWith(".class")) {
+ int slash = name.lastIndexOf('/');
+ if (slash == -1) continue;
+
+ String pname = name.substring(0, slash);
+ if (table.get(pname) == null) {
+ table.put(pname, new Object());
+ }
+ }
+ }
+ }
+ } catch (IOException e) {
+ System.err.println("Ignoring " + filename + " (" + e.getMessage() + ")");
+ //e.printStackTrace();
+ }
+ }
+
+
+ /**
+ * Make list of package names by traversing a directory hierarchy.
+ * Each time a class is found in a folder, add its containing set
+ * of folders to the package list. If another folder is found,
+ * walk down into that folder and continue.
+ */
+ static private void packageListFromFolder(File dir, String sofar,
+ Hashtable table) {
+ //String imports[],
+ //int importCount) {
+ //System.err.println("checking dir '" + dir + "'");
+ boolean foundClass = false;
+ String files[] = dir.list();
+
+ for (int i = 0; i < files.length; i++) {
+ if (files[i].equals(".") || files[i].equals("..")) continue;
+
+ File sub = new File(dir, files[i]);
+ if (sub.isDirectory()) {
+ String nowfar =
+ (sofar == null) ? files[i] : (sofar + "." + files[i]);
+ packageListFromFolder(sub, nowfar, table);
+ //System.out.println(nowfar);
+ //imports[importCount++] = nowfar;
+ //importCount = magicImportsRecursive(sub, nowfar,
+ // imports, importCount);
+ } else if (!foundClass) { // if no classes found in this folder yet
+ if (files[i].endsWith(".class")) {
+ //System.out.println("unique class: " + files[i] + " for " + sofar);
+ table.put(sofar, new Object());
+ foundClass = true;
+ }
+ }
+ }
+ }
+}
diff --git a/app/src/processing/app/debug/EventThread.java b/app/src/processing/app/debug/EventThread.java
new file mode 100644
index 000000000..918600f1f
--- /dev/null
+++ b/app/src/processing/app/debug/EventThread.java
@@ -0,0 +1,424 @@
+/*
+ * @(#)EventThread.java 1.4 03/01/23
+ *
+ * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+ * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 1997-2001 by Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Sun grants you ("Licensee") a non-exclusive, royalty free, license to use,
+ * modify and redistribute this software in source and binary code form,
+ * provided that i) this copyright notice and license appear on all copies of
+ * the software; and ii) Licensee does not utilize the software in a manner
+ * which is disparaging to Sun.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
+ * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
+ * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
+ * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS
+ * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
+ * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
+ * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
+ * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * This software is not designed or intended for use in on-line control of
+ * aircraft, air traffic, aircraft navigation or aircraft communications; or in
+ * the design, construction, operation or maintenance of any nuclear
+ * facility. Licensee represents and warrants that it will not use or
+ * redistribute the Software for such purposes.
+ */
+
+package processing.app.debug;
+
+import java.io.PrintWriter;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import com.sun.jdi.Field;
+import com.sun.jdi.IncompatibleThreadStateException;
+import com.sun.jdi.ThreadReference;
+import com.sun.jdi.VMDisconnectedException;
+import com.sun.jdi.Value;
+import com.sun.jdi.VirtualMachine;
+import com.sun.jdi.event.ClassPrepareEvent;
+import com.sun.jdi.event.Event;
+import com.sun.jdi.event.EventIterator;
+import com.sun.jdi.event.EventQueue;
+import com.sun.jdi.event.EventSet;
+import com.sun.jdi.event.ExceptionEvent;
+import com.sun.jdi.event.MethodEntryEvent;
+import com.sun.jdi.event.MethodExitEvent;
+import com.sun.jdi.event.ModificationWatchpointEvent;
+import com.sun.jdi.event.StepEvent;
+import com.sun.jdi.event.ThreadDeathEvent;
+import com.sun.jdi.event.VMDeathEvent;
+import com.sun.jdi.event.VMDisconnectEvent;
+import com.sun.jdi.event.VMStartEvent;
+import com.sun.jdi.request.EventRequest;
+import com.sun.jdi.request.EventRequestManager;
+import com.sun.jdi.request.ExceptionRequest;
+import com.sun.jdi.request.ModificationWatchpointRequest;
+import com.sun.jdi.request.StepRequest;
+
+/**
+ * This class processes incoming JDI events and displays them
+ *
+ * @version @(#) EventThread.java 1.4 03/01/23 23:33:38
+ * @author Robert Field
+ */
+public class EventThread extends Thread {
+
+ private final Runner parent;
+ private final VirtualMachine vm; // Running VM
+ private final String[] excludes; // Packages to exclude
+ private final PrintWriter writer; // Where output goes
+
+ static String nextBaseIndent = ""; // Starting indent for next thread
+
+ private boolean connected = true; // Connected to VM
+ private boolean vmDied = true; // VMDeath occurred
+
+ // Maps ThreadReference to ThreadTrace instances
+ private Map traceMap = new HashMap();
+
+ EventThread(Runner parent, VirtualMachine vm, String[] excludes, PrintWriter writer) {
+ super("event-handler");
+ this.parent = parent;
+ this.vm = vm;
+ this.excludes = excludes;
+ this.writer = writer;
+ }
+
+ /**
+ * Run the event handling thread.
+ * As long as we are connected, get event sets off
+ * the queue and dispatch the events within them.
+ */
+ public void run() {
+ EventQueue queue = vm.eventQueue();
+ while (connected) {
+ try {
+ EventSet eventSet = queue.remove();
+ EventIterator it = eventSet.eventIterator();
+ while (it.hasNext()) {
+ handleEvent(it.nextEvent());
+ }
+ eventSet.resume();
+ } catch (InterruptedException exc) {
+ // Ignore
+ } catch (VMDisconnectedException discExc) {
+ handleDisconnectedException();
+ break;
+ }
+ }
+ }
+
+ /**
+ * Create the desired event requests, and enable
+ * them so that we will get events.
+ * @param excludes Class patterns for which we don't want events
+ * @param watchFields Do we want to watch assignments to fields
+ */
+ void setEventRequests(boolean watchFields) {
+ EventRequestManager mgr = vm.eventRequestManager();
+
+// VMDeathRequest deathReq = mgr.createVMDeathRequest();
+// deathReq.setSuspendPolicy(EventRequest.SUSPEND_ALL);
+// deathReq.enable();
+
+ // want all exceptions
+ ExceptionRequest excReq = mgr.createExceptionRequest(null, false, true);
+ //ExceptionRequest excReq = mgr.createExceptionRequest(null, true, true);
+ // suspend so we can step
+ excReq.setSuspendPolicy(EventRequest.SUSPEND_ALL);
+ excReq.enable();
+
+ /*
+ MethodEntryRequest menr = mgr.createMethodEntryRequest();
+ for (int i=0; i 0) {
+ indent.append("| ");
+ }
+
+ EventRequestManager mgr = vm.eventRequestManager();
+ mgr.deleteEventRequest(event.request());
+ }
+
+ void threadDeathEvent(ThreadDeathEvent event) {
+ indent = new StringBuffer(baseIndent);
+ println("====== " + thread.name() + " end ======");
+ }
+ }
+
+ /**
+ * Returns the ThreadTrace instance for the specified thread,
+ * creating one if needed.
+ */
+ ThreadTrace threadTrace(ThreadReference thread) {
+ ThreadTrace trace = (ThreadTrace)traceMap.get(thread);
+ if (trace == null) {
+ trace = new ThreadTrace(thread);
+ traceMap.put(thread, trace);
+ }
+ return trace;
+ }
+
+ /**
+ * Dispatch incoming events
+ */
+ private void handleEvent(Event event) {
+ if (event instanceof ExceptionEvent) {
+ exceptionEvent((ExceptionEvent)event);
+ } else if (event instanceof ModificationWatchpointEvent) {
+ fieldWatchEvent((ModificationWatchpointEvent)event);
+ } else if (event instanceof MethodEntryEvent) {
+ methodEntryEvent((MethodEntryEvent)event);
+ } else if (event instanceof MethodExitEvent) {
+ methodExitEvent((MethodExitEvent)event);
+ } else if (event instanceof StepEvent) {
+ stepEvent((StepEvent)event);
+ } else if (event instanceof ThreadDeathEvent) {
+ threadDeathEvent((ThreadDeathEvent)event);
+ } else if (event instanceof ClassPrepareEvent) {
+ classPrepareEvent((ClassPrepareEvent)event);
+ } else if (event instanceof VMStartEvent) {
+ vmStartEvent((VMStartEvent)event);
+ } else if (event instanceof VMDeathEvent) {
+ vmDeathEvent((VMDeathEvent)event);
+ } else if (event instanceof VMDisconnectEvent) {
+ vmDisconnectEvent((VMDisconnectEvent)event);
+ } else {
+ throw new Error("Unexpected event type");
+ }
+ }
+
+ /***
+ * A VMDisconnectedException has happened while dealing with
+ * another event. We need to flush the event queue, dealing only
+ * with exit events (VMDeath, VMDisconnect) so that we terminate
+ * correctly.
+ */
+ synchronized void handleDisconnectedException() {
+ EventQueue queue = vm.eventQueue();
+ while (connected) {
+ try {
+ EventSet eventSet = queue.remove();
+ EventIterator iter = eventSet.eventIterator();
+ while (iter.hasNext()) {
+ Event event = iter.nextEvent();
+ if (event instanceof VMDeathEvent) {
+ vmDeathEvent((VMDeathEvent)event);
+ } else if (event instanceof VMDisconnectEvent) {
+ vmDisconnectEvent((VMDisconnectEvent)event);
+ }
+ }
+ eventSet.resume(); // Resume the VM
+ } catch (InterruptedException exc) {
+ // ignore
+ }
+ }
+ }
+
+ private void vmStartEvent(VMStartEvent event) {
+ if (writer != null) writer.println("-- VM Started --");
+ }
+
+ // Forward event for thread specific processing
+ private void methodEntryEvent(MethodEntryEvent event) {
+ threadTrace(event.thread()).methodEntryEvent(event);
+ }
+
+ // Forward event for thread specific processing
+ private void methodExitEvent(MethodExitEvent event) {
+ threadTrace(event.thread()).methodExitEvent(event);
+ }
+
+ // Forward event for thread specific processing
+ private void stepEvent(StepEvent event) {
+ threadTrace(event.thread()).stepEvent(event);
+ }
+
+ // Forward event for thread specific processing
+ private void fieldWatchEvent(ModificationWatchpointEvent event) {
+ threadTrace(event.thread()).fieldWatchEvent(event);
+ }
+
+ void threadDeathEvent(ThreadDeathEvent event) {
+ ThreadTrace trace = (ThreadTrace)traceMap.get(event.thread());
+ if (trace != null) { // only want threads we care about
+ trace.threadDeathEvent(event); // Forward event
+ }
+ }
+
+ /**
+ * A new class has been loaded.
+ * Set watchpoints on each of its fields
+ */
+ private void classPrepareEvent(ClassPrepareEvent event) {
+// System.out.println(event);
+// List list = event.referenceType().methodsByName("stop");
+// Object o = list.get(0);
+// System.out.println("stop methods = " + list);
+// System.out.println(o.getClass());
+
+ EventRequestManager mgr = vm.eventRequestManager();
+ List fields = event.referenceType().visibleFields();
+ for (Iterator it = fields.iterator(); it.hasNext(); ) {
+ Field field = (Field)it.next();
+ ModificationWatchpointRequest req =
+ mgr.createModificationWatchpointRequest(field);
+ for (int i=0; i
+ * Different instances of MessageStream need to do different things with
+ * messages. In particular, a stream instance used for parsing output from
+ * the compiler compiler has to interpret its messages differently than one
+ * parsing output from the runtime.
+ *
+ * Classes which consume messages and do something with them
+ * should implement this interface.
+ */
+public interface MessageConsumer {
+
+ public void message(String s);
+
+}
diff --git a/app/src/processing/app/debug/MessageSiphon.java b/app/src/processing/app/debug/MessageSiphon.java
new file mode 100644
index 000000000..60b3e8c32
--- /dev/null
+++ b/app/src/processing/app/debug/MessageSiphon.java
@@ -0,0 +1,87 @@
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+/*
+ Part of the Processing project - http://processing.org
+
+ Copyright (c) 2004-06 Ben Fry and Casey Reas
+ Copyright (c) 2001-04 Massachusetts Institute of Technology
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+package processing.app.debug;
+
+import java.io.*;
+
+
+/**
+ * Slurps up messages from compiler.
+ */
+class MessageSiphon implements Runnable {
+ BufferedReader streamReader;
+ Thread thread;
+ MessageConsumer consumer;
+
+
+ public MessageSiphon(InputStream stream, MessageConsumer consumer) {
+ this.streamReader = new BufferedReader(new InputStreamReader(stream));
+ this.consumer = consumer;
+
+ thread = new Thread(this);
+ // don't set priority too low, otherwise exceptions won't
+ // bubble up in time (i.e. compile errors have a weird delay)
+ //thread.setPriority(Thread.MIN_PRIORITY);
+ thread.setPriority(Thread.MAX_PRIORITY-1);
+ //thread.start();
+ }
+
+
+ public void run() {
+ try {
+ // process data until we hit EOF; this will happily block
+ // (effectively sleeping the thread) until new data comes in.
+ // when the program is finally done, null will come through.
+ //
+ String currentLine;
+ while ((currentLine = streamReader.readLine()) != null) {
+ // \n is added again because readLine() strips it out
+ //EditorConsole.systemOut.println("messaging in");
+ consumer.message(currentLine + "\n");
+ //EditorConsole.systemOut.println("messaging out");
+ }
+ //EditorConsole.systemOut.println("messaging thread done");
+ thread = null;
+
+ } catch (NullPointerException npe) {
+ // Fairly common exception during shutdown
+ thread = null;
+
+ } catch (Exception e) {
+ // On Linux and sometimes on Mac OS X, a "bad file descriptor"
+ // message comes up when closing an applet that's run externally.
+ // That message just gets supressed here..
+ String mess = e.getMessage();
+ if ((mess != null) &&
+ (mess.indexOf("Bad file descriptor") != -1)) {
+ //if (e.getMessage().indexOf("Bad file descriptor") == -1) {
+ //System.err.println("MessageSiphon err " + e);
+ //e.printStackTrace();
+ } else {
+ e.printStackTrace();
+ }
+ thread = null;
+ }
+ }
+}
diff --git a/app/src/processing/app/debug/MessageStream.java b/app/src/processing/app/debug/MessageStream.java
new file mode 100644
index 000000000..9ea7caeb9
--- /dev/null
+++ b/app/src/processing/app/debug/MessageStream.java
@@ -0,0 +1,62 @@
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+/*
+ Part of the Processing project - http://processing.org
+
+ Copyright (c) 2004-08 Ben Fry and Casey Reas
+ Copyright (c) 2001-04 Massachusetts Institute of Technology
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+package processing.app.debug;
+
+import java.io.*;
+
+
+/**
+ * OutputStream to handle stdout/stderr messages.
+ *
+ * This is used by Editor, System.err is set to
+ * new PrintStream(new MessageStream()).
+ * It's also used by Compiler.
+ */
+class MessageStream extends OutputStream {
+
+ MessageConsumer messageConsumer;
+
+ public MessageStream(MessageConsumer messageConsumer) {
+ this.messageConsumer = messageConsumer;
+ }
+
+ public void close() { }
+
+ public void flush() { }
+
+ public void write(byte b[]) {
+ // this never seems to get called
+ System.out.println("leech1: " + new String(b));
+ }
+
+ public void write(byte b[], int offset, int length) {
+ //System.out.println("leech2: " + new String(b));
+ this.messageConsumer.message(new String(b, offset, length));
+ }
+
+ public void write(int b) {
+ // this never seems to get called
+ System.out.println("leech3: '" + ((char)b) + "'");
+ }
+}
diff --git a/app/src/processing/app/debug/Runner.java b/app/src/processing/app/debug/Runner.java
new file mode 100644
index 000000000..b63f6ed74
--- /dev/null
+++ b/app/src/processing/app/debug/Runner.java
@@ -0,0 +1,1039 @@
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+/*
+ Part of the Processing project - http://processing.org
+
+ Copyright (c) 2004-08 Ben Fry and Casey Reas
+ Copyright (c) 2001-04 Massachusetts Institute of Technology
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+package processing.app.debug;
+
+import processing.app.*;
+import processing.core.*;
+
+import java.awt.Point;
+import java.io.*;
+import java.util.*;
+
+import com.sun.jdi.*;
+import com.sun.jdi.connect.*;
+import com.sun.jdi.event.ExceptionEvent;
+
+
+/**
+ * Runs a compiled sketch. As of release 0136, all sketches are run externally
+ * to the environment so that a debugging interface can be used. This opens up
+ * future options for a decent debugger, but in the meantime fixes several
+ * problems with output and error streams, messages getting lost on Mac OS X,
+ * the run/stop buttons not working, libraries not shutting down, exceptions
+ * not coming through, exceptions being printed twice, having to force quit
+ * if you make a bad while() loop, and so on.
+ */
+public class Runner implements MessageConsumer {
+
+ private boolean presenting;
+
+ // Object that listens for error messages or exceptions.
+ private RunnerListener listener;
+
+ // Running remote VM
+ private VirtualMachine vm;
+
+ // Thread transferring remote error stream to our error stream
+ private Thread errThread = null;
+
+ // Thread transferring remote output stream to our output stream
+ private Thread outThread = null;
+
+ // Mode for tracing the Trace program (default= 0 off)
+ private int debugTraceMode = 0;
+
+ // Do we want to watch assignments to fields
+ private boolean watchFields = false;
+
+ // Class patterns for which we don't want events
+ private String[] excludes = {
+ "java.*", "javax.*", "sun.*", "com.sun.*",
+ "apple.*",
+ "processing.*"
+ };
+
+ private RunnerException exception;
+ //private PrintStream leechErr;
+
+ private Editor editor;
+ private Sketch sketch;
+ private String appletClassName;
+
+// private boolean newMessage;
+// private int messageLineCount;
+// private boolean foundMessageSource;
+//
+// private SystemOutSiphon processInput;
+// private OutputStream processOutput;
+// private MessageSiphon processError;
+
+
+ public Runner(Sketch sketch, String appletClassName,
+ boolean presenting, RunnerListener listener) {
+ this.sketch = sketch;
+ this.appletClassName = appletClassName;
+ this.presenting = presenting;
+ this.listener = listener;
+
+ if (listener instanceof Editor) {
+ this.editor = (Editor) listener;
+ }
+ }
+
+
+ public void launch() {
+ // TODO entire class is a total mess as of release 0136.
+ // This will be cleaned up significantly over the next couple months.
+
+ // all params have to be stored as separate items,
+ // so a growable array needs to be used. i.e. -Xms128m -Xmx1024m
+ // will throw an error if it's shoved into a single array element
+ //Vector params = new Vector();
+
+ // get around Apple's Java 1.5 bugs
+ //params.add("/System/Library/Frameworks/JavaVM.framework/Versions/1.4.2/Commands/java");
+ //params.add("java");
+ //System.out.println("0");
+
+ String[] machineParamList = getMachineParams();
+ String[] sketchParamList = getSketchParams();
+
+ vm = launchVirtualMachine(machineParamList, sketchParamList);
+ if (vm != null) {
+ generateTrace(null);
+// try {
+// generateTrace(new PrintWriter("/Users/fry/Desktop/output.txt"));
+// } catch (Exception e) {
+// e.printStackTrace();
+// }
+ }
+ }
+
+
+ protected String[] getMachineParams() {
+ ArrayList params = new ArrayList();
+
+ //params.add("-Xint"); // interpreted mode
+ //params.add("-Xprof"); // profiler
+ //params.add("-Xaprof"); // allocation profiler
+ //params.add("-Xrunhprof:cpu=samples"); // old-style profiler
+
+ // TODO change this to use run.args = true, run.args.0, run.args.1, etc.
+ // so that spaces can be included in the arg names
+ String options = Preferences.get("run.options");
+ if (options.length() > 0) {
+ String pieces[] = PApplet.split(options, ' ');
+ for (int i = 0; i < pieces.length; i++) {
+ String p = pieces[i].trim();
+ if (p.length() > 0) {
+ params.add(p);
+ }
+ }
+ }
+
+// params.add("-Djava.ext.dirs=nuffing");
+
+ if (Preferences.getBoolean("run.options.memory")) {
+ params.add("-Xms" + Preferences.get("run.options.memory.initial") + "m");
+ params.add("-Xmx" + Preferences.get("run.options.memory.maximum") + "m");
+ }
+
+ if (Base.isMacOS()) {
+ params.add("-Xdock:name=" + appletClassName);
+// params.add("-Dcom.apple.mrj.application.apple.menu.about.name=" +
+// sketch.getMainClassName());
+ }
+ // sketch.libraryPath might be ""
+ // librariesClassPath will always have sep char prepended
+ params.add("-Djava.library.path=" +
+ sketch.getLibraryPath() +
+ File.pathSeparator +
+ System.getProperty("java.library.path"));
+
+ params.add("-cp");
+ params.add(sketch.getClassPath());
+// params.add(sketch.getClassPath() +
+// File.pathSeparator +
+// Base.librariesClassPath);
+
+ //PApplet.println(PApplet.split(sketch.classPath, ':'));
+
+ String outgoing[] = new String[params.size()];
+ params.toArray(outgoing);
+
+ //PApplet.println(outgoing);
+// PApplet.println(PApplet.split(outgoing[0], ":"));
+// PApplet.println();
+// PApplet.println("class path");
+// PApplet.println(PApplet.split(outgoing[2], ":"));
+
+ return outgoing;
+ //return (String[]) params.toArray();
+
+// System.out.println("sketch class path");
+// PApplet.println(PApplet.split(sketch.classPath, ';'));
+// System.out.println();
+// System.out.println("libraries class path");
+// PApplet.println(PApplet.split(Base.librariesClassPath, ';'));
+// System.out.println();
+ }
+
+
+ protected String[] getSketchParams() {
+ ArrayList params = new ArrayList();
+
+ params.add("processing.core.PApplet");
+
+ // If there was a saved location (this guy has been run more than once)
+ // then the location will be set to the last position of the sketch window.
+ // This will be passed to the PApplet runner using something like
+ // --location=30,20
+ // Otherwise, the editor location will be passed, and the applet will
+ // figure out where to place itself based on the editor location.
+ // --editor-location=150,20
+ if (editor != null) { // if running processing-cmd, don't do placement
+ Point windowLocation = editor.getSketchLocation();
+ if (windowLocation != null) {
+ params.add(PApplet.ARGS_LOCATION + "=" +
+ windowLocation.x + "," + windowLocation.y);
+ } else {
+ Point editorLocation = editor.getLocation();
+ params.add(PApplet.ARGS_EDITOR_LOCATION + "=" +
+ editorLocation.x + "," + editorLocation.y);
+ }
+ params.add(PApplet.ARGS_EXTERNAL);
+ }
+
+ params.add(PApplet.ARGS_DISPLAY + "=" +
+ Preferences.get("run.display"));
+ params.add(PApplet.ARGS_SKETCH_FOLDER + "=" +
+ sketch.getFolder().getAbsolutePath());
+
+ if (presenting) {
+ params.add(PApplet.ARGS_PRESENT);
+ if (Preferences.getBoolean("run.present.exclusive")) {
+ params.add(PApplet.ARGS_EXCLUSIVE);
+ }
+ params.add(PApplet.ARGS_STOP_COLOR + "=" +
+ Preferences.get("run.present.stop.color"));
+ params.add(PApplet.ARGS_BGCOLOR + "=" +
+ Preferences.get("run.present.bgcolor"));
+ }
+
+ params.add(appletClassName);
+
+// String outgoing[] = new String[params.size()];
+// params.toArray(outgoing);
+// return outgoing;
+ return (String[]) params.toArray(new String[0]);
+ }
+
+
+ /*
+ protected VirtualMachine launchVirtualMachine_sun(String[] vmParams, String[] classParams) {
+ //vm = launchTarget(sb.toString());
+ LaunchingConnector connector =
+ findLaunchingConnector("com.sun.jdi.CommandLineLaunch");
+ //Map arguments = connectorArguments(connector, mainArgs);
+
+ PApplet.println(connector); // gets the defaults
+
+ Map arguments = connector.defaultArguments();
+ //System.out.println(arguments);
+
+// for (Iterator itr = arguments.keySet().iterator(); itr.hasNext(); ) {
+// Connector.Argument argument =
+// (Connector.Argument) arguments.get(itr.next());
+// System.out.println(argument);
+// }
+
+ //connector.transport().
+
+ Connector.Argument mainArg =
+ (Connector.Argument)arguments.get("main");
+ if (mainArg == null) {
+ throw new Error("Bad launching connector");
+ }
+ String mainArgs = "";
+ //mainArgs = addArgument(mainArgs, className);
+ if (classParams != null) {
+ for (int i = 0; i < classParams.length; i++) {
+ mainArgs = addArgument(mainArgs, classParams[i], ' ');
+ }
+ }
+ mainArg.setValue(mainArgs);
+
+ //System.out.println("main args are: ");
+ //System.out.println(mainArgs);
+
+// if (watchFields) {
+// // We need a VM that supports watchpoints
+// Connector.Argument optionArg =
+// (Connector.Argument)arguments.get("options");
+// if (optionArg == null) {
+// throw new Error("Bad launching connector");
+// }
+// optionArg.setValue("-classic");
+// }
+ String optionArgs = "";
+ for (int i = 0; i < vmParams.length; i++) {
+ optionArgs = addArgument(optionArgs, vmParams[i], ' ');
+ }
+ // prevent any incorrect transport address b.s. from being added
+ // -Xrunjdwp:transport=dt_socket,address=cincinnati118.ipcorporate.com:55422,suspend=y
+ //optionArgs = addArgument(optionArgs, "-agentlib:jdwp=transport=dt_socket,address=localhost:12345,suspend=y", ' ');
+ //optionArgs += " -Xrunjdwp:transport=dt_socket,address=localhost:55422,suspend=y";
+ //optionArgs = optionArgs + " -agentlib:jdwp=transport=dt_socket";
+ //optionArgs = addArgument(optionArgs, "-Xrunjdwp:transport=dt_socket,address=localhost:55422,suspend=y", ' ');
+
+ //optionArgs = addArgument(optionArgs, "address=127.0.0.1:54321", ' ');
+ //optionArgs = addArgument(optionArgs, "localAddress", ' ');
+
+ Connector.Argument optionArg =
+ (Connector.Argument)arguments.get("options");
+ optionArg.setValue(optionArgs);
+
+// Connector.Argument addressArg =
+// (Connector.Argument)arguments.get("address");
+ //arguments.put("raw.address", new Connector.Argument("blah"));
+ //PApplet.println("it's gonna be " + addressArg);
+
+ //arguments.put("address", "localhost");
+
+// Connector.Argument addressArg =
+// (Connector.Argument)arguments.get("address");
+// addressArg.setValue("localhost");
+
+// System.out.println("option args are: ");
+// System.out.println(arguments.get("options"));
+
+ System.out.println("args are " + arguments);
+
+ // com.sun.tools.jdi.SunCommandLineLauncher
+
+ // http://java.sun.com/j2se/1.5.0/docs/guide/jpda/conninv.html#sunlaunch
+ try {
+ return connector.launch(arguments);
+ } catch (IOException exc) {
+ throw new Error("Unable to launch target VM: " + exc);
+ } catch (IllegalConnectorArgumentsException exc) {
+ throw new Error("Internal error: " + exc);
+ } catch (VMStartException exc) {
+ exc.printStackTrace();
+ System.err.println();
+ System.err.println("Could not run the sketch.");
+ System.err.println("Make sure that you haven't set the maximum available memory too high.");
+ System.err.println("For more information, read revisions.txt and Help -> Troubleshooting.");
+ //System.err.println("Target VM failed to initialize:");
+ //System.err.println("msg is " + exc.getMessage());
+ //exc.printStackTrace();
+ //throw new Error("Target VM failed to initialize: " +
+ //exc.getMessage());
+ //throw new Error(exc.getMessage());
+ //throw new RunnerException(exc.getMessage());
+ //editor.error(exc);
+ editor.error("Could not run the sketch.");
+ return null;
+ }
+ }
+ */
+
+
+ protected VirtualMachine launchVirtualMachine(String[] vmParams,
+ String[] classParams) {
+ //vm = launchTarget(sb.toString());
+ LaunchingConnector connector =
+ findLaunchingConnector("com.sun.jdi.RawCommandLineLaunch");
+ //PApplet.println(connector); // gets the defaults
+
+ //Map arguments = connectorArguments(connector, mainArgs);
+ Map arguments = connector.defaultArguments();
+
+ Connector.Argument commandArg =
+ (Connector.Argument)arguments.get("command");
+ // Using localhost instead of 127.0.0.1 sometimes causes a
+ // "Transport Error 202" error message when trying to run.
+ // http://dev.processing.org/bugs/show_bug.cgi?id=895
+ String addr = "127.0.0.1:" + (8000 + (int) (Math.random() * 1000));
+ //String addr = "localhost:" + (8000 + (int) (Math.random() * 1000));
+ //String addr = "" + (8000 + (int) (Math.random() * 1000));
+
+ String commandArgs = Base.isWindows() ?
+ "java -Xrunjdwp:transport=dt_shmem,address=" + addr + ",suspend=y " :
+ "java -Xrunjdwp:transport=dt_socket,address=" + addr + ",suspend=y ";
+ //String commandArgs = "java -agentlib:jdwp=transport=dt_socket,address=" + addr + ",suspend=y ";
+ //String commandArgs = "java -agentlib:jdwp=transport=dt_socket,address=" + addr + ",server=n,suspend=y ";
+ for (int i = 0; i < vmParams.length; i++) {
+ commandArgs = addArgument(commandArgs, vmParams[i], ' ');
+ }
+ if (classParams != null) {
+ for (int i = 0; i < classParams.length; i++) {
+ commandArgs = addArgument(commandArgs, classParams[i], ' ');
+ }
+ }
+ commandArg.setValue(commandArgs);
+
+ Connector.Argument addressArg =
+ (Connector.Argument)arguments.get("address");
+ addressArg.setValue(addr);
+
+ //PApplet.println(connector); // prints the current
+ //com.sun.tools.jdi.AbstractLauncher al;
+ //com.sun.tools.jdi.RawCommandLineLauncher rcll;
+
+ //System.out.println(PApplet.javaVersion);
+ // http://java.sun.com/j2se/1.5.0/docs/guide/jpda/conninv.html#sunlaunch
+ try {
+ return connector.launch(arguments);
+ } catch (IOException exc) {
+ throw new Error("Unable to launch target VM: " + exc);
+ } catch (IllegalConnectorArgumentsException exc) {
+ throw new Error("Internal error: " + exc);
+ } catch (VMStartException exc) {
+ Process p = exc.process();
+ //System.out.println(p);
+ String[] errorStrings = PApplet.loadStrings(p.getErrorStream());
+ /*String[] inputStrings =*/ PApplet.loadStrings(p.getInputStream());
+
+ if (errorStrings != null && errorStrings.length > 1) {
+ if (errorStrings[0].indexOf("Invalid maximum heap size") != -1) {
+ Base.showWarning("Way Too High",
+ "Please lower the value for \u201Cmaximum available memory\u201D in the\n" +
+ "Preferences window. For more information, read Help \u2192 Troubleshooting.",
+ exc);
+ } else {
+ PApplet.println(errorStrings);
+ System.err.println("Using startup command:");
+ PApplet.println(arguments);
+ }
+ } else {
+ exc.printStackTrace();
+ System.err.println("Could not run the sketch (Target VM failed to initialize).");
+ if (Preferences.getBoolean("run.options.memory")) {
+ // Only mention this if they've even altered the memory setup
+ System.err.println("Make sure that you haven't set the maximum available memory too high.");
+ }
+ System.err.println("For more information, read revisions.txt and Help \u2192 Troubleshooting.");
+ }
+ if (editor != null) {
+ listener.statusError("Could not run the sketch.");
+ }
+ return null;
+ }
+ }
+
+
+ private static boolean hasWhitespace(String string) {
+ int length = string.length();
+ for (int i = 0; i < length; i++) {
+ if (Character.isWhitespace(string.charAt(i))) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+ private static String addArgument(String string, String argument, char sep) {
+ if (hasWhitespace(argument) || argument.indexOf(',') != -1) {
+ // Quotes were stripped out for this argument, add 'em back.
+ StringBuffer buffer = new StringBuffer(string);
+ buffer.append('"');
+ for (int i = 0; i < argument.length(); i++) {
+ char c = argument.charAt(i);
+ if (c == '"') {
+ buffer.append('\\');
+ }
+ buffer.append(c);
+ }
+ buffer.append('\"');
+ buffer.append(sep);
+ return buffer.toString();
+ } else {
+ return string + argument + String.valueOf(sep);
+ }
+ }
+
+
+ /**
+ * Generate the trace.
+ * Enable events, start thread to display events,
+ * start threads to forward remote error and output streams,
+ * resume the remote VM, wait for the final event, and shutdown.
+ */
+ void generateTrace(PrintWriter writer) {
+ vm.setDebugTraceMode(debugTraceMode);
+
+ EventThread eventThread = null;
+ //if (writer != null) {
+ eventThread = new EventThread(this, vm, excludes, writer);
+ eventThread.setEventRequests(watchFields);
+ eventThread.start();
+ //}
+
+ //redirectOutput();
+
+ Process process = vm.process();
+
+// processInput = new SystemOutSiphon(process.getInputStream());
+// processError = new MessageSiphon(process.getErrorStream(), this);
+
+ // Copy target's output and error to our output and error.
+// errThread = new StreamRedirectThread("error reader",
+// process.getErrorStream(),
+// System.err);
+ MessageSiphon ms = new MessageSiphon(process.getErrorStream(), this);
+ errThread = ms.thread;
+
+ outThread = new StreamRedirectThread("output reader",
+ process.getInputStream(),
+ System.out);
+
+ errThread.start();
+ outThread.start();
+
+ vm.resume();
+ //System.out.println("done with resume");
+
+ // Shutdown begins when event thread terminates
+ try {
+ if (eventThread != null) eventThread.join();
+ // Bug #852 tracked to this next line in the code.
+ // http://dev.processing.org/bugs/show_bug.cgi?id=852
+ errThread.join(); // Make sure output is forwarded
+ outThread.join(); // before we exit
+ //System.out.println("out of it");
+
+ // At this point, disable the run button.
+ // This happens when the sketch is exited by hitting ESC,
+ // or the user manually closes the sketch window.
+ // TODO this should be handled better, should it not?
+ if (editor != null) {
+ editor.internalRunnerClosed();
+ }
+
+ } catch (InterruptedException exc) {
+ // we don't interrupt
+ }
+ //System.out.println("and leaving");
+ if (writer != null) writer.close();
+ }
+
+
+ /**
+ * Find a com.sun.jdi.CommandLineLaunch connector
+ */
+ LaunchingConnector findLaunchingConnector(String connectorName) {
+ //VirtualMachineManager mgr = Bootstrap.virtualMachineManager();
+
+ // Get the default connector.
+ // Not useful here since they all need different args.
+// System.out.println(Bootstrap.virtualMachineManager().defaultConnector());
+// return Bootstrap.virtualMachineManager().defaultConnector();
+
+ List connectors = Bootstrap.virtualMachineManager().allConnectors();
+
+ // code to list available connectors
+// Iterator iter2 = connectors.iterator();
+// while (iter2.hasNext()) {
+// Connector connector = (Connector)iter2.next();
+// System.out.println("connector name is " + connector.name());
+// }
+
+ Iterator iter = connectors.iterator();
+ while (iter.hasNext()) {
+ Connector connector = (Connector)iter.next();
+ if (connector.name().equals(connectorName)) {
+ return (LaunchingConnector)connector;
+ }
+ }
+ throw new Error("No launching connector");
+ }
+
+
+ public void exception(ExceptionEvent event) {
+ ObjectReference or = event.exception();
+ ReferenceType rt = or.referenceType();
+ String exceptionName = rt.name();
+ //Field messageField = Throwable.class.getField("detailMessage");
+ Field messageField = rt.fieldByName("detailMessage");
+// System.out.println("field " + messageField);
+ Value messageValue = or.getValue(messageField);
+// System.out.println("mess val " + messageValue);
+
+ int last = exceptionName.lastIndexOf('.');
+ String message = exceptionName.substring(last + 1);
+ if (messageValue != null) {
+ String messageStr = messageValue.toString();
+ if (messageStr.startsWith("\"")) {
+ messageStr = messageStr.substring(1, messageStr.length() - 1);
+ }
+ message += ": " + messageStr;
+ }
+// System.out.println("mess type " + messageValue.type());
+ //StringReference messageReference = (StringReference) messageValue.type();
+
+// System.out.println(or.referenceType().fields());
+// if (name.startsWith("java.lang.")) {
+// name = name.substring(10);
+ if (exceptionName.equals("java.lang.OutOfMemoryError")) {
+ listener.statusError("OutOfMemoryError: You may need to increase the memory setting in Preferences.");
+ System.err.println("An OutOfMemoryError means that your code is either using up too much memory");
+ System.err.println("because of a bug (e.g. creating an array that's too large, or unintentionally");
+ System.err.println("loading thousands of images), or that your sketch may need more memory to run.");
+ System.err.println("If your sketch uses a lot of memory (for instance if it loads a lot of data files)");
+ System.err.println("you can increase the memory available to your sketch using the Preferences window.");
+
+ } else if (exceptionName.equals("java.lang.StackOverflowError")) {
+ listener.statusError("StackOverflowError: This sketch is attempting too much recursion.");
+ System.err.println("A StackOverflowError means that you have a bug that's causing a function");
+ System.err.println("to be called recursively (it's calling itself and going in circles),");
+ System.err.println("or you're intentionally calling a recursive function too much,");
+ System.err.println("and your code should be rewritten in a more efficient manner.");
+
+ } else if (exceptionName.equals("java.lang.UnsupportedClassVersionError")) {
+ listener.statusError("UnsupportedClassVersionError: A library is using code compiled with an unsupported version of Java.");
+ System.err.println("This version of Processing only supports libraries and JAR files compiled for Java 1.5.");
+ System.err.println("A library used by this sketch was compiled for Java 1.6 or later, ");
+ System.err.println("and needs to be recompiled to be compatible with Java 1.5.");
+
+ } else if (exceptionName.equals("java.lang.NoSuchMethodError") || exceptionName.equals("java.lang.NoSuchFieldError")) {
+ listener.statusError(exceptionName.substring(10) + ": You're probably using a library that's incompatible with this version of Processing.");
+
+ } else if (message.equals("ClassNotFoundException: quicktime.std.StdQTException")) {
+ listener.statusError("Could not find QuickTime, please reinstall QuickTime 7 or later.");
+
+ } else {
+ reportException(message, event.thread());
+ }
+ editor.internalRunnerClosed();
+ }
+
+
+ // This may be called more than one time per error in the VM,
+ // presumably because exceptions might be wrapped inside others,
+ // and this will fire for both.
+ protected void reportException(String message, ThreadReference thread) {
+ try {
+ int codeIndex = -1;
+ int lineNumber = -1;
+
+ // Any of the thread.blah() methods can throw an AbsentInformationEx
+ // if that bit of data is missing. If so, just write out the error
+ // message to the console.
+ List frames = thread.frames();
+ for (StackFrame frame : frames) {
+ //System.out.println("frame: " + frame);
+ Location location = frame.location();
+ String filename = null;
+ filename = location.sourceName();
+ lineNumber = location.lineNumber();
+
+ String appletJavaFile = appletClassName + ".java";
+ SketchCode errorCode = null;
+ if (filename.equals(appletJavaFile)) {
+ for (SketchCode code : sketch.getCode()) {
+ if (code.isExtension("pde")) {
+ if (lineNumber >= code.getPreprocOffset()) {
+ errorCode = code;
+ }
+ }
+ }
+ } else {
+ for (SketchCode code : sketch.getCode()) {
+ if (code.isExtension("java")) {
+ if (filename.equals(code.getFileName())) {
+ errorCode = code;
+ }
+ }
+ }
+ }
+ codeIndex = sketch.getCodeIndex(errorCode);
+
+ if (codeIndex != -1) {
+ //System.out.println("got line num " + lineNumber);
+ // in case this was a tab that got embedded into the main .java
+ lineNumber -= sketch.getCode(codeIndex).getPreprocOffset();
+
+ // lineNumber is 1-indexed, but editor wants zero-indexed
+ lineNumber--;
+
+ // getMessage() will be what's shown in the editor
+ exception = new RunnerException(message, codeIndex, lineNumber, -1);
+ exception.hideStackTrace();
+ listener.statusError(exception);
+ return;
+ }
+ }
+ } catch (AbsentInformationException e) {
+ //e.printStackTrace(); // not useful
+ exception = new RunnerException(message);
+ exception.hideStackTrace();
+ listener.statusError(exception);
+
+ } catch (IncompatibleThreadStateException e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ public void close() {
+ // TODO make sure stop() has already been called to exit the sketch
+
+ // TODO actually kill off the vm here
+ if (vm != null) {
+ try {
+ vm.exit(0);
+
+ } catch (com.sun.jdi.VMDisconnectedException vmde) {
+ // if the vm has disconnected on its own, ignore message
+ //System.out.println("harmless disconnect " + vmde.getMessage());
+ // TODO shouldn't need to do this, need to do more cleanup
+ }
+ vm = null;
+ }
+
+ //if (window != null) window.hide();
+// if (window != null) {
+// //System.err.println("disposing window");
+// window.dispose();
+// window = null;
+// }
+
+ /*
+ if (process != null) {
+ try {
+ process.destroy();
+ } catch (Exception e) {
+ //System.err.println("(ignored) error while destroying");
+ //e.printStackTrace();
+ }
+ process = null;
+ }
+ */
+ }
+
+
+ // made synchronized for rev 87
+ // attempted to remove synchronized for 0136 to fix bug #775 (no luck tho)
+ // http://dev.processing.org/bugs/show_bug.cgi?id=775
+ synchronized public void message(String s) {
+ //System.out.println("M" + s.length() + ":" + s.trim()); // + "MMM" + s.length());
+
+ // this eats the CRLFs on the lines.. oops.. do it later
+ //if (s.trim().length() == 0) return;
+
+ // this is PApplet sending a message (via System.out.println)
+ // that signals that the applet has been quit.
+ if (s.indexOf(PApplet.EXTERNAL_STOP) == 0) {
+ //System.out.println("external: quit");
+ editor.internalCloseRunner();
+ return;
+ }
+
+ // this is the PApplet sending us a message that the applet
+ // is being moved to a new window location
+ if (s.indexOf(PApplet.EXTERNAL_MOVE) == 0) {
+ String nums = s.substring(s.indexOf(' ') + 1).trim();
+ int space = nums.indexOf(' ');
+ int left = Integer.parseInt(nums.substring(0, space));
+ int top = Integer.parseInt(nums.substring(space + 1));
+ editor.setSketchLocation(new Point(left, top));
+ //System.out.println("external: move to " + left + " " + top);
+ return;
+ }
+
+ // Removed while doing cleaning for 0145,
+ // it seems that this is never actually printed out.
+ /*
+ // this is PApplet sending a message saying "i'm about to spew
+ // a stack trace because an error occurred during PApplet.run()"
+ if (s.indexOf(PApplet.LEECH_WAKEUP) == 0) {
+ // newMessage being set to 'true' means that the next time
+ // message() is called, expect the first line of the actual
+ // error message & stack trace to be sent from the applet.
+ newMessage = true;
+ return; // this line ignored
+ }
+ */
+
+ // these are used for debugging, in case there are concerns
+ // that some errors aren't coming through properly
+ /*
+ if (s.length() > 2) {
+ System.err.println(newMessage);
+ System.err.println("message " + s.length() + ":" + s);
+ }
+ */
+ // always shove out the mesage, since it might not fall under
+ // the same setup as we're expecting
+ System.err.print(s);
+ //System.err.println("[" + s.length() + "] " + s);
+ System.err.flush();
+
+// // exit here because otherwise the exception name
+// // may be titled with a blank string
+// if (s.trim().length() == 0) return;
+//
+// // annoying, because it seems as though the terminators
+// // aren't being sent properly
+// //System.err.println(s);
+//
+// //if (newMessage && s.length() > 2) {
+// if (newMessage) {
+// exception = new RunnerException(s); // type of java ex
+// exception.hideStackTrace();
+// //System.out.println("setting ex type to " + s);
+// newMessage = false;
+// foundMessageSource = false;
+// messageLineCount = 0;
+//
+// } else {
+// messageLineCount++;
+//
+// /*
+//java.lang.NullPointerException
+// at javatest.(javatest.java:5)
+// at Temporary_2425_1153.draw(Temporary_2425_1153.java:11)
+// at PApplet.nextFrame(PApplet.java:481)
+// at PApplet.run(PApplet.java:428)
+// at java.lang.Thread.run(Unknown Source)
+// */
+//
+// if (!foundMessageSource) {
+// // " at javatest.(javatest.java:5)"
+// // -> "javatest.(javatest.java:5)"
+// int atIndex = s.indexOf("at ");
+// if (atIndex == -1) {
+// //System.err.println(s); // stop double-printing exceptions
+// return;
+// }
+// s = s.substring(atIndex + 3);
+//
+// // added for 0124 to improve error handling
+// // not highlighting lines if it's in the p5 code
+// if (s.startsWith("processing.")) return;
+// // no highlight if it's java.lang.whatever
+// if (s.startsWith("java.")) return;
+//
+// // "javatest.(javatest.java:5)"
+// // -> "javatest." and "(javatest.java:5)"
+// int startParen = s.indexOf('(');
+// // at javatest.(javatest.java:5)
+// //String pkgClassFxn = null;
+// //String fileLine = null;
+// int codeIndex = -1;
+// int lineNumber = -1;
+//
+// if (startParen == -1) {
+// //pkgClassFxn = s;
+//
+// } else {
+// //pkgClassFxn = s.substring(0, startParen);
+//
+// // "(javatest.java:5)"
+// String fileAndLine = s.substring(startParen + 1);
+// int stopParen = fileAndLine.indexOf(')');
+// //fileAndLine = fileAndLine.substring(0, fileAndLine.length() - 1);
+// fileAndLine = fileAndLine.substring(0, stopParen);
+// //System.out.println("file 'n line " + fileAndLine);
+//
+// //if (!fileAndLine.equals("Unknown Source")) {
+// // "javatest.java:5"
+// int colonIndex = fileAndLine.indexOf(':');
+// if (colonIndex != -1) {
+// String filename = fileAndLine.substring(0, colonIndex);
+// // "javatest.java" and "5"
+// //System.out.println("filename = " + filename);
+// //System.out.println("pre0 = " + sketch.code[0].preprocName);
+// //for (int i = 0; i < sketch.codeCount; i++) {
+// //System.out.println(i + " " + sketch.code[i].lineOffset + " " +
+// // sketch.code[i].preprocName);
+// //}
+// lineNumber =
+// Integer.parseInt(fileAndLine.substring(colonIndex + 1)) - 1;
+//
+// for (int i = 0; i < sketch.getCodeCount(); i++) {
+// SketchCode code = sketch.getCode(i);
+// //System.out.println(code.preprocName + " " + lineNumber + " " +
+// // code.preprocOffset);
+// if (((code.preprocName == null) &&
+// (lineNumber >= code.preprocOffset)) ||
+// ((code.preprocName != null) &&
+// code.preprocName.equals(filename))) {
+// codeIndex = i;
+// //System.out.println("got codeindex " + codeIndex);
+// //break;
+// //} else if (
+// }
+// }
+//
+// if (codeIndex != -1) {
+// //System.out.println("got line num " + lineNumber);
+// // in case this was a tab that got embedded into the main .java
+// lineNumber -= sketch.getCode(codeIndex).preprocOffset;
+//
+// // this may have a paren on the end, if so need to strip
+// // down to just the digits
+// /*
+// int lastNumberIndex = colonIndex + 1;
+// while ((lastNumberIndex < fileAndLine.length()) &&
+// Character.isDigit(fileAndLine.charAt(lastNumberIndex))) {
+// lastNumberIndex++;
+// }
+// */
+//
+// // lineNumber is 1-indexed, but editor wants zero-indexed
+// // getMessage() will be what's shown in the editor
+// exception =
+// new RunnerException(exception.getMessage(),
+// codeIndex, lineNumber, -1);
+// exception.hideStackTrace();
+// foundMessageSource = true;
+// }
+// }
+// }
+// editor.error(exception);
+//
+// /*
+// int index = s.indexOf(className + ".java");
+// if (index != -1) {
+// int len = (className + ".java").length();
+// String lineNumberStr = s.substring(index + len + 1);
+// index = lineNumberStr.indexOf(')');
+// lineNumberStr = lineNumberStr.substring(0, index);
+// try {
+// exception.line = Integer.parseInt(lineNumberStr) - 1; //2;
+// } catch (NumberFormatException e) { }
+// //e.printStackTrace(); // a recursive error waiting to happen?
+// // if nfe occurs, who cares, still send the error on up
+// editor.error(exception);
+// */
+//
+// /*
+// // WARNING THESE ARE DISABLED!!
+// } else if ((index = s.indexOf(className + ".class")) != -1) {
+// // code to check for:
+// // at Temporary_484_3845.loop(Compiled Code)
+// // would also probably get:
+// // at Temporary_484_3845.loop
+// // which (i believe) is used by the mac and/or jview
+// String functionStr = s.substring(index +
+// (className + ".class").length() + 1);
+// index = functionStr.indexOf('(');
+// if (index != -1) {
+// functionStr = functionStr.substring(0, index);
+// }
+// exception = new RunnerException(//"inside \"" + functionStr + "()\": " +
+// exception.getMessage() +
+// " inside " + functionStr + "() " +
+// "[add Compiler.disable() to setup()]");
+// editor.error(exception);
+// // this will fall through in tihs example:
+// // at Temporary_4636_9696.pootie(Compiled Code)
+// // at Temporary_4636_9696.loop(Temporary_4636_9696.java:24)
+// // because pootie() (re)sets the exception title
+// // and throws it, but then the line number gets set
+// // because of the line that comes after
+// */
+//
+// } else if (messageLineCount > 10) { // 5 -> 10 for 0088
+// // this means the class name may not be mentioned
+// // in the stack trace.. this is just a general purpose
+// // error, but needs to make it through anyway.
+// // so if five lines have gone past, might as well signal
+// messageLineCount = -100;
+// exception = new RunnerException(exception.getMessage());
+// exception.hideStackTrace();
+// editor.error(exception);
+//
+// } else {
+// //System.err.print(s);
+// }
+// //System.out.println("got it " + s);
+// }
+ }
+
+
+ //////////////////////////////////////////////////////////////
+
+
+ /**
+ * Siphons from an InputStream of System.out (from a Process)
+ * and sends it to the real System.out.
+ */
+ class SystemOutSiphon implements Runnable {
+ InputStream input;
+ Thread thread;
+
+ public SystemOutSiphon(InputStream input) {
+ this.input = input;
+
+ thread = new Thread(this);
+ // unless this is set to min, it seems to hork the app
+ // since it's in charge of stuffing the editor console with strings
+ // maybe it's time to get rid of/fix that friggin console
+ // ...disabled for 0075, with 0074's fix for code folder hanging
+ // this only seems to make the console unresponsive
+ //thread.setPriority(Thread.MIN_PRIORITY);
+ thread.start();
+ }
+
+ public void run() {
+ byte boofer[] = new byte[256];
+
+ while (Thread.currentThread() == thread) {
+ try {
+ // can't use a buffered reader here because incremental
+ // print statements are interesting too.. causes some
+ // disparity with how System.err gets spewed, oh well.
+ int count = input.read(boofer, 0, boofer.length);
+ if (count == -1) {
+ thread = null;
+
+ } else {
+ System.out.print(new String(boofer, 0, count));
+ //System.out.flush();
+ }
+
+ } catch (IOException e) {
+ // this is prolly because the app was quit & the stream broken
+ //e.printStackTrace(System.out);
+ //e.printStackTrace();
+ thread = null;
+
+ } catch (Exception e) {
+ //System.out.println("SystemOutSiphon: i just died in your arms tonight");
+ // on mac os x, this will spew a "Bad File Descriptor" ex
+ // each time an external app is shut down.
+ //e.printStackTrace();
+ thread = null;
+ //System.out.println("");
+ }
+ //System.out.println("SystemOutSiphon: out");
+ //thread = null;
+ }
+ }
+ }
+}
diff --git a/app/src/processing/app/debug/RunnerException.java b/app/src/processing/app/debug/RunnerException.java
new file mode 100644
index 000000000..0b4e59154
--- /dev/null
+++ b/app/src/processing/app/debug/RunnerException.java
@@ -0,0 +1,147 @@
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+/*
+ Part of the Processing project - http://processing.org
+
+ Copyright (c) 2004-08 Ben Fry and Casey Reas
+ Copyright (c) 2001-04 Massachusetts Institute of Technology
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+package processing.app.debug;
+
+
+/**
+ * An exception with a line number attached that occurs
+ * during either compile time or run time.
+ */
+public class RunnerException extends Exception /*RuntimeException*/ {
+ protected String message;
+ protected int codeIndex;
+ protected int codeLine;
+ protected int codeColumn;
+ protected boolean showStackTrace;
+
+
+ public RunnerException(String message) {
+ this(message, -1, -1, -1, true);
+ }
+
+
+ public RunnerException(String message, int file, int line, int column) {
+ this(message, file, line, column, true);
+ }
+
+
+ public RunnerException(String message, int file, int line, int column,
+ boolean showStackTrace) {
+ this.message = message;
+ this.codeIndex = file;
+ this.codeLine = line;
+ this.codeColumn = column;
+ this.showStackTrace = showStackTrace;
+ }
+
+
+ /**
+ * Override getMessage() in Throwable, so that I can set
+ * the message text outside the constructor.
+ */
+ public String getMessage() {
+ return message;
+ }
+
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+
+ public int getCodeIndex() {
+ return codeIndex;
+ }
+
+
+ public void setCodeIndex(int index) {
+ codeIndex = index;
+ }
+
+
+ public boolean hasCodeIndex() {
+ return codeIndex != -1;
+ }
+
+
+ public int getCodeLine() {
+ return codeLine;
+ }
+
+
+ public void setCodeLine(int line) {
+ this.codeLine = line;
+ }
+
+
+ public boolean hasCodeLine() {
+ return codeLine != -1;
+ }
+
+
+ public void setCodeColumn(int column) {
+ this.codeColumn = column;
+ }
+
+
+ public int getCodeColumn() {
+ return codeColumn;
+ }
+
+
+ public void showStackTrace() {
+ showStackTrace = true;
+ }
+
+
+ public void hideStackTrace() {
+ showStackTrace = false;
+ }
+
+
+ /**
+ * Nix the java.lang crap out of an exception message
+ * because it scares the children.
+ *
+ * This function must be static to be used with super()
+ * in each of the constructors above.
+ */
+ /*
+ static public final String massage(String msg) {
+ if (msg.indexOf("java.lang.") == 0) {
+ //int dot = msg.lastIndexOf('.');
+ msg = msg.substring("java.lang.".length());
+ }
+ return msg;
+ //return (dot == -1) ? msg : msg.substring(dot+1);
+ }
+ */
+
+
+ public void printStackTrace() {
+ if (showStackTrace) {
+ super.printStackTrace();
+ }
+ }
+}
diff --git a/app/src/processing/app/debug/RunnerListener.java b/app/src/processing/app/debug/RunnerListener.java
new file mode 100644
index 000000000..1728d7972
--- /dev/null
+++ b/app/src/processing/app/debug/RunnerListener.java
@@ -0,0 +1,31 @@
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+/*
+ Part of the Processing project - http://processing.org
+
+ Copyright (c) 2008 Ben Fry and Casey Reas
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+package processing.app.debug;
+
+
+public interface RunnerListener {
+
+ public void statusError(String message);
+
+ public void statusError(Exception exception);
+}
\ No newline at end of file
diff --git a/app/src/processing/app/debug/StreamRedirectThread.java b/app/src/processing/app/debug/StreamRedirectThread.java
new file mode 100644
index 000000000..795e8c199
--- /dev/null
+++ b/app/src/processing/app/debug/StreamRedirectThread.java
@@ -0,0 +1,84 @@
+/*
+ * @(#)StreamRedirectThread.java 1.4 03/01/23
+ *
+ * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+ * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 1997-2001 by Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Sun grants you ("Licensee") a non-exclusive, royalty free, license to use,
+ * modify and redistribute this software in source and binary code form,
+ * provided that i) this copyright notice and license appear on all copies of
+ * the software; and ii) Licensee does not utilize the software in a manner
+ * which is disparaging to Sun.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
+ * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
+ * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
+ * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS
+ * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
+ * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
+ * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
+ * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * This software is not designed or intended for use in on-line control of
+ * aircraft, air traffic, aircraft navigation or aircraft communications; or in
+ * the design, construction, operation or maintenance of any nuclear
+ * facility. Licensee represents and warrants that it will not use or
+ * redistribute the Software for such purposes.
+ */
+package processing.app.debug;
+
+import java.io.*;
+
+/**
+ * StreamRedirectThread is a thread which copies it's input to
+ * it's output and terminates when it completes.
+ *
+ * @version @(#) StreamRedirectThread.java 1.4 03/01/23 23:33:38
+ * @author Robert Field
+ */
+public class StreamRedirectThread extends Thread {
+
+ private final Reader in;
+ private final Writer out;
+
+ private static final int BUFFER_SIZE = 2048;
+
+ /**
+ * Set up for copy.
+ * @param name Name of the thread
+ * @param in Stream to copy from
+ * @param out Stream to copy to
+ */
+ public StreamRedirectThread(String name, InputStream in, OutputStream out) {
+ super(name);
+ this.in = new InputStreamReader(in);
+ this.out = new OutputStreamWriter(out);
+ setPriority(Thread.MAX_PRIORITY-1);
+ }
+
+ /**
+ * Copy.
+ */
+ public void run() {
+ try {
+ char[] cbuf = new char[BUFFER_SIZE];
+ int count;
+ //System.out.println("opening streamredirectthread");
+ while ((count = in.read(cbuf, 0, BUFFER_SIZE)) >= 0) {
+ out.write(cbuf, 0, count);
+ // had to add the flush() here.. maybe shouldn't be using writer? [fry]
+ out.flush();
+ }
+ //System.out.println("exiting streamredirectthread");
+ out.flush();
+ } catch(IOException exc) {
+ System.err.println("Child I/O Transfer - " + exc);
+ }
+ }
+}
diff --git a/app/src/processing/app/linux/Platform.java b/app/src/processing/app/linux/Platform.java
new file mode 100644
index 000000000..7f227596f
--- /dev/null
+++ b/app/src/processing/app/linux/Platform.java
@@ -0,0 +1,106 @@
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+/*
+ Part of the Processing project - http://processing.org
+
+ Copyright (c) 2008 Ben Fry and Casey Reas
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+package processing.app.linux;
+
+import java.io.File;
+
+import javax.swing.UIManager;
+
+import processing.app.Preferences;
+
+
+/**
+ * Used by Base for platform-specific tweaking, for instance finding the
+ * sketchbook location using the Windows registry, or OS X event handling.
+ */
+public class Platform extends processing.app.Platform {
+
+ // TODO Need to be smarter here since KDE people ain't gonna like that GTK.
+ // It may even throw a weird exception at 'em for their trouble.
+ public void setLookAndFeel() throws Exception {
+ // Linux is by default even uglier than metal (Motif?).
+ // Actually, i'm using native menus, so they're even uglier
+ // and Motif-looking (Lesstif?). Ick. Need to fix this.
+ //String lfname = UIManager.getCrossPlatformLookAndFeelClassName();
+ //UIManager.setLookAndFeel(lfname);
+
+ // For 0120, trying out the gtk+ look and feel as the default.
+ // This is available in Java 1.4.2 and later, and it can't possibly
+ // be any worse than Metal. (Ocean might also work, but that's for
+ // Java 1.5, and we aren't going there yet)
+ UIManager.setLookAndFeel("com.sun.java.swing.plaf.gtk.GTKLookAndFeel");
+ }
+
+
+ public void openURL(String url) throws Exception {
+ if (openFolderAvailable()) {
+ String launcher = Preferences.get("launcher");
+ if (launcher != null) {
+ Runtime.getRuntime().exec(new String[] { launcher, url });
+ }
+ }
+ }
+
+
+ public boolean openFolderAvailable() {
+ if (Preferences.get("launcher") != null) {
+ return true;
+ }
+
+ // Attempt to use gnome-open
+ try {
+ Process p = Runtime.getRuntime().exec(new String[] { "gnome-open" });
+ /*int result =*/ p.waitFor();
+ // Not installed will throw an IOException (JDK 1.4.2, Ubuntu 7.04)
+ Preferences.set("launcher", "gnome-open");
+ return true;
+ } catch (Exception e) { }
+
+ // Attempt with kde-open
+ try {
+ Process p = Runtime.getRuntime().exec(new String[] { "kde-open" });
+ /*int result =*/ p.waitFor();
+ Preferences.set("launcher", "kde-open");
+ return true;
+ } catch (Exception e) { }
+
+ return false;
+ }
+
+
+ public void openFolder(File file) throws Exception {
+ if (openFolderAvailable()) {
+ String lunch = Preferences.get("launcher");
+ try {
+ String[] params = new String[] { lunch, file.getAbsolutePath() };
+ //processing.core.PApplet.println(params);
+ /*Process p =*/ Runtime.getRuntime().exec(params);
+ /*int result =*/ //p.waitFor();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ } else {
+ System.out.println("not available");
+ }
+ }
+}
diff --git a/app/src/processing/app/macosx/Platform.java b/app/src/processing/app/macosx/Platform.java
new file mode 100644
index 000000000..0b440cb6a
--- /dev/null
+++ b/app/src/processing/app/macosx/Platform.java
@@ -0,0 +1,184 @@
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+/*
+ Part of the Processing project - http://processing.org
+
+ Copyright (c) 2008 Ben Fry and Casey Reas
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+package processing.app.macosx;
+
+import java.awt.Insets;
+import java.io.File;
+import java.io.FileNotFoundException;
+
+import javax.swing.UIManager;
+
+import com.apple.eio.FileManager;
+
+import processing.app.Base;
+
+
+/**
+ * Platform handler for Mac OS X.
+ */
+public class Platform extends processing.app.Platform {
+
+ public void setLookAndFeel() throws Exception {
+ // Use the Quaqua L & F on OS X to make JFileChooser less awful
+ UIManager.setLookAndFeel("ch.randelshofer.quaqua.QuaquaLookAndFeel");
+ // undo quaqua trying to fix the margins, since we've already
+ // hacked that in, bit by bit, over the years
+ UIManager.put("Component.visualMargin", new Insets(1, 1, 1, 1));
+ }
+
+
+ public void init(Base base) {
+ ThinkDifferent.init(base);
+ /*
+ try {
+ String name = "processing.app.macosx.ThinkDifferent";
+ Class osxAdapter = ClassLoader.getSystemClassLoader().loadClass(name);
+
+ Class[] defArgs = { Base.class };
+ Method registerMethod = osxAdapter.getDeclaredMethod("register", defArgs);
+ if (registerMethod != null) {
+ Object[] args = { this };
+ registerMethod.invoke(osxAdapter, args);
+ }
+ } catch (NoClassDefFoundError e) {
+ // This will be thrown first if the OSXAdapter is loaded on a system without the EAWT
+ // because OSXAdapter extends ApplicationAdapter in its def
+ System.err.println("This version of Mac OS X does not support the Apple EAWT." +
+ "Application Menu handling has been disabled (" + e + ")");
+
+ } catch (ClassNotFoundException e) {
+ // This shouldn't be reached; if there's a problem with the OSXAdapter
+ // we should get the above NoClassDefFoundError first.
+ System.err.println("This version of Mac OS X does not support the Apple EAWT. " +
+ "Application Menu handling has been disabled (" + e + ")");
+ } catch (Exception e) {
+ System.err.println("Exception while loading BaseOSX:");
+ e.printStackTrace();
+ }
+ */
+ }
+
+
+ public File getSettingsFolder() throws Exception {
+ return new File(getLibraryFolder(), "Processing");
+ }
+
+
+ public File getDefaultSketchbookFolder() throws Exception {
+ return new File(getDocumentsFolder(), "Processing");
+ /*
+ // looking for /Users/blah/Documents/Processing
+ try {
+ Class clazz = Class.forName("processing.app.BaseMacOS");
+ Method m = clazz.getMethod("getDocumentsFolder", new Class[] { });
+ String documentsPath = (String) m.invoke(null, new Object[] { });
+ sketchbookFolder = new File(documentsPath, "Processing");
+
+ } catch (Exception e) {
+ sketchbookFolder = promptSketchbookLocation();
+ }
+ */
+ }
+
+
+ public void openURL(String url) throws Exception {
+ if (!url.startsWith("http://")) {
+ // Assume this is a file instead, and just open it.
+ // Extension of http://dev.processing.org/bugs/show_bug.cgi?id=1010
+ processing.core.PApplet.open(url);
+
+ /*
+ // prepend file:// on this guy since it's a file
+ url = "file://" + url;
+
+ // replace spaces with %20 for the file url
+ // otherwise the mac doesn't like to open it
+ // can't just use URLEncoder, since that makes slashes into
+ // %2F characters, which is no good. some might say "useless"
+ if (url.indexOf(' ') != -1) {
+ StringBuffer sb = new StringBuffer();
+ char c[] = url.toCharArray();
+ for (int i = 0; i < c.length; i++) {
+ if (c[i] == ' ') {
+ sb.append("%20");
+ } else {
+ sb.append(c[i]);
+ }
+ }
+ url = sb.toString();
+ }
+ */
+ }
+ com.apple.eio.FileManager.openURL(url);
+ }
+
+
+ public boolean openFolderAvailable() {
+ return true;
+ }
+
+
+ public void openFolder(File file) throws Exception {
+ //openURL(file.getAbsolutePath()); // handles char replacement, etc
+ processing.core.PApplet.open(file.getAbsolutePath());
+ }
+
+
+ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+
+
+ // Some of these are supposedly constants in com.apple.eio.FileManager,
+ // however they don't seem to link properly from Eclipse.
+
+ static final int kDocumentsFolderType =
+ ('d' << 24) | ('o' << 16) | ('c' << 8) | 's';
+ //static final int kPreferencesFolderType =
+ // ('p' << 24) | ('r' << 16) | ('e' << 8) | 'f';
+ static final int kDomainLibraryFolderType =
+ ('d' << 24) | ('l' << 16) | ('i' << 8) | 'b';
+ static final short kUserDomain = -32763;
+
+
+ // apple java extensions documentation
+ // http://developer.apple.com/documentation/Java/Reference/1.5.0
+ // /appledoc/api/com/apple/eio/FileManager.html
+
+ // carbon folder constants
+ // http://developer.apple.com/documentation/Carbon/Reference
+ // /Folder_Manager/folder_manager_ref/constant_6.html#/
+ // /apple_ref/doc/uid/TP30000238/C006889
+
+ // additional information found int the local file:
+ // /System/Library/Frameworks/CoreServices.framework
+ // /Versions/Current/Frameworks/CarbonCore.framework/Headers/
+
+
+ protected String getLibraryFolder() throws FileNotFoundException {
+ return FileManager.findFolder(kUserDomain, kDomainLibraryFolderType);
+ }
+
+
+ protected String getDocumentsFolder() throws FileNotFoundException {
+ return FileManager.findFolder(kUserDomain, kDocumentsFolderType);
+ }
+}
\ No newline at end of file
diff --git a/app/src/processing/app/macosx/ThinkDifferent.java b/app/src/processing/app/macosx/ThinkDifferent.java
new file mode 100644
index 000000000..38cb6cb9a
--- /dev/null
+++ b/app/src/processing/app/macosx/ThinkDifferent.java
@@ -0,0 +1,126 @@
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+/*
+ Part of the Processing project - http://processing.org
+
+ Copyright (c) 2007 Ben Fry and Casey Reas
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+package processing.app.macosx;
+
+import processing.app.Base;
+
+import com.apple.eawt.*;
+
+
+/**
+ * Deal with issues related to thinking different. This handles the basic
+ * Mac OS X menu commands (and apple events) for open, about, prefs, etc.
+ *
+ * Based on OSXAdapter.java from Apple DTS.
+ *
+ * As of 0140, this code need not be built on platforms other than OS X,
+ * because of the new platform structure which isolates through reflection.
+ */
+public class ThinkDifferent implements ApplicationListener {
+
+ // pseudo-singleton model; no point in making multiple instances
+ // of the EAWT application or our adapter
+ private static ThinkDifferent adapter;
+ // http://developer.apple.com/documentation/Java/Reference/1.4.2/appledoc/api/com/apple/eawt/Application.html
+ private static Application application;
+
+ // reference to the app where the existing quit, about, prefs code is
+ private Base base;
+
+
+ static protected void init(Base base) {
+ if (application == null) {
+ application = new com.apple.eawt.Application();
+ }
+ if (adapter == null) {
+ adapter = new ThinkDifferent(base);
+ }
+ application.addApplicationListener(adapter);
+ application.setEnabledAboutMenu(true);
+ application.setEnabledPreferencesMenu(true);
+ }
+
+
+ public ThinkDifferent(Base base) {
+ this.base = base;
+ }
+
+
+ // implemented handler methods. These are basically hooks into existing
+ // functionality from the main app, as if it came over from another platform.
+ public void handleAbout(ApplicationEvent ae) {
+ if (base != null) {
+ ae.setHandled(true);
+ base.handleAbout();
+ } else {
+ throw new IllegalStateException("handleAbout: Base instance detached from listener");
+ }
+ }
+
+
+ public void handlePreferences(ApplicationEvent ae) {
+ if (base != null) {
+ base.handlePrefs();
+ ae.setHandled(true);
+ } else {
+ throw new IllegalStateException("handlePreferences: Base instance detached from listener");
+ }
+ }
+
+
+ public void handleOpenApplication(ApplicationEvent ae) {
+ }
+
+
+ public void handleOpenFile(ApplicationEvent ae) {
+ String filename = ae.getFilename();
+ base.handleOpen(filename);
+ ae.setHandled(true);
+ }
+
+
+ public void handlePrintFile(ApplicationEvent ae) {
+ // TODO implement os x print handler here (open app, call handlePrint, quit)
+ }
+
+
+ public void handleQuit(ApplicationEvent ae) {
+ if (base != null) {
+ /*
+ / You MUST setHandled(false) if you want to delay or cancel the quit.
+ / This is important for cross-platform development -- have a universal quit
+ / routine that chooses whether or not to quit, so the functionality is identical
+ / on all platforms. This example simply cancels the AppleEvent-based quit and
+ / defers to that universal method.
+ */
+ boolean result = base.handleQuit();
+ ae.setHandled(result);
+ } else {
+ throw new IllegalStateException("handleQuit: Base instance detached from listener");
+ }
+ }
+
+
+ public void handleReOpenApplication(ApplicationEvent arg0) {
+ }
+}
\ No newline at end of file
diff --git a/app/src/processing/app/preproc/.cvsignore b/app/src/processing/app/preproc/.cvsignore
new file mode 100644
index 000000000..b010c249c
--- /dev/null
+++ b/app/src/processing/app/preproc/.cvsignore
@@ -0,0 +1,9 @@
+*Lexer.java
+*Recognizer.java
+*TokenTypes.java
+*TokenTypes.txt
+*TreeParser.java
+*TreeParserTokenTypes.java
+*TreeParserTokenTypes.txt
+expanded*.g
+
diff --git a/app/src/processing/app/preproc/PdeEmitter.java b/app/src/processing/app/preproc/PdeEmitter.java
new file mode 100644
index 000000000..f4634f32e
--- /dev/null
+++ b/app/src/processing/app/preproc/PdeEmitter.java
@@ -0,0 +1,936 @@
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+package processing.app.preproc;
+
+import processing.app.*;
+import processing.app.debug.RunnerException;
+
+
+/* Based on original code copyright (c) 2003 Andy Tripp .
+ * shipped under GPL with permission.
+ */
+
+//import antlr.*;
+import antlr.collections.*;
+//import antlr.collections.impl.*;
+import java.io.*;
+//import java.util.*;
+
+/**
+ * PDEEmitter: A class that can take an ANTLR Java AST and produce
+ * reasonably formatted Java code from it. To use it, create a
+ * PDEEmitter object, call setOut() if you want to print to something
+ * other than System.out, and then call print(), passing the
+ * AST. Typically, the AST node that you pass would be the root of a
+ * tree - the ROOT_ID node that represents a Java file.
+ */
+
+@SuppressWarnings("unused")
+public class PdeEmitter implements PdeTokenTypes
+{
+ private PrintStream out = System.out;
+ private PrintStream debug = System.err;
+ //private static int ALL = -1;
+ private java.util.Stack stack = new java.util.Stack();
+ private static String[] tokenNames;
+ private final static int ROOT_ID = 0;
+ static {
+ setupTokenNames();
+ }
+
+ /*
+ private static Hashtable publicMethods;
+ private static final String publicMethodList[] = {
+ "setup", "draw", //"loop",
+ "mousePressed", "mouseReleased", "mouseClicked",
+ "mouseEntered", "mouseExited",
+ "mouseMoved", "mouseDragged",
+ "keyPressed", "keyReleased", "keyTyped"
+ };
+
+ static {
+ publicMethods = new Hashtable();
+ for (int i = 0; i < publicMethodList.length; i++) {
+ publicMethods.put(publicMethodList[i], new Object());
+ }
+ }
+ */
+
+ // Map each AST token type to a String
+ private static void setupTokenNames() {
+ tokenNames = new String[200];
+ for (int i=0; i>=";
+ tokenNames[BSR_ASSIGN]=">>>=";
+ tokenNames[SL_ASSIGN]="<<=";
+ tokenNames[BAND_ASSIGN]="&=";
+ tokenNames[BXOR_ASSIGN]="^=";
+ tokenNames[BOR_ASSIGN]="|=";
+ tokenNames[QUESTION]="?";
+ tokenNames[LOR]="||";
+ tokenNames[LAND]="&&";
+ tokenNames[BOR]="|";
+ tokenNames[BXOR]="^";
+ tokenNames[BAND]="&";
+ tokenNames[NOT_EQUAL]="!=";
+ tokenNames[EQUAL]="==";
+ tokenNames[LT]="<";
+ tokenNames[GT]=">";
+ tokenNames[LE]="<=";
+ tokenNames[GE]=">=";
+ tokenNames[SL]="<<";
+ tokenNames[SR]=">>";
+ tokenNames[BSR]=">>>";
+ tokenNames[PLUS]="+";
+ tokenNames[MINUS]="-";
+ tokenNames[DIV]="/";
+ tokenNames[MOD]="%";
+ tokenNames[INC]="++";
+ tokenNames[DEC]="--";
+ tokenNames[BNOT]="~";
+ tokenNames[LNOT]="!";
+ tokenNames[FINAL]="final";
+ tokenNames[ABSTRACT]="abstract";
+ tokenNames[LITERAL_package]="package";
+ tokenNames[LITERAL_import]="import";
+ tokenNames[LITERAL_void]="void";
+ tokenNames[LITERAL_boolean]="boolean";
+ tokenNames[LITERAL_byte]="byte";
+ tokenNames[LITERAL_char]="char";
+ tokenNames[LITERAL_short]="short";
+ tokenNames[LITERAL_int]="int";
+ tokenNames[LITERAL_float]="float";
+ tokenNames[LITERAL_long]="long";
+ tokenNames[LITERAL_double]="double";
+ tokenNames[LITERAL_private]="private";
+ tokenNames[LITERAL_public]="public";
+ tokenNames[LITERAL_protected]="protected";
+ tokenNames[LITERAL_static]="static";
+ tokenNames[LITERAL_transient]="transient";
+ tokenNames[LITERAL_native]="native";
+ tokenNames[LITERAL_threadsafe]="threadsafe";
+ tokenNames[LITERAL_synchronized]="synchronized";
+ tokenNames[LITERAL_volatile]="volatile";
+ tokenNames[LITERAL_class]="class";
+ tokenNames[LITERAL_extends]="extends";
+ tokenNames[LITERAL_interface]="interface";
+ tokenNames[LITERAL_implements]="implements";
+ tokenNames[LITERAL_throws]="throws";
+ tokenNames[LITERAL_if]="if";
+ tokenNames[LITERAL_else]="else";
+ tokenNames[LITERAL_for]="for";
+ tokenNames[LITERAL_while]="while";
+ tokenNames[LITERAL_do]="do";
+ tokenNames[LITERAL_break]="break";
+ tokenNames[LITERAL_continue]="continue";
+ tokenNames[LITERAL_return]="return";
+ tokenNames[LITERAL_switch]="switch";
+ tokenNames[LITERAL_throw]="throw";
+ tokenNames[LITERAL_case]="case";
+ tokenNames[LITERAL_default]="default";
+ tokenNames[LITERAL_try]="try";
+ tokenNames[LITERAL_finally]="finally";
+ tokenNames[LITERAL_catch]="catch";
+ tokenNames[LITERAL_instanceof]="instanceof";
+ tokenNames[LITERAL_this]="this";
+ tokenNames[LITERAL_super]="super";
+ tokenNames[LITERAL_true]="true";
+ tokenNames[LITERAL_false]="false";
+ tokenNames[LITERAL_null]="null";
+ tokenNames[LITERAL_new]="new";
+ tokenNames[LITERAL_color]="int"; // PDE specific alias
+ }
+
+ /**
+ * Specify a PrintStream to print to. System.out is the default.
+ * @param out the PrintStream to print to
+ */
+ public void setOut(PrintStream out) {
+ this.out = out;
+ }
+ private String name(AST ast) {
+ return tokenNames[ast.getType()];
+ }
+ private String name(int type) {
+ return tokenNames[type];
+ }
+
+ /**
+ * Find a child of the given AST that has the given type
+ * @returns a child AST of the given type. If it can't find a child of the
+ * given type, return null.
+ */
+ private AST getChild(AST ast, int childType) {
+ AST child = ast.getFirstChild();
+ while (child != null) {
+ if (child.getType() == childType) {
+ // debug.println("getChild: found:" + name(ast));
+ return child;
+ }
+ child = child.getNextSibling();
+ }
+ return null;
+ }
+
+ /**
+ * Dump the list of hidden tokens linked to after the AST node passed in.
+ * Most hidden tokens are dumped from this function.
+ */
+ private void dumpHiddenAfter(AST ast) {
+ dumpHiddenTokens(((antlr.CommonASTWithHiddenTokens)ast).getHiddenAfter());
+ }
+
+ /**
+ * Dump the list of hidden tokens linked to before the AST node passed in.
+ * The only time hidden tokens need to be dumped with this function is when
+ * dealing parts of the tree where automatic tree construction was
+ * turned off with the ! operator in the grammar file and the nodes were
+ * manually constructed in such a way that the usual tokens don't have the
+ * necessary hiddenAfter links.
+ */
+ private void dumpHiddenBefore(AST ast) {
+
+ antlr.CommonHiddenStreamToken
+ child = null,
+ parent = ((antlr.CommonASTWithHiddenTokens)ast).getHiddenBefore();
+
+ // if there aren't any hidden tokens here, quietly return
+ //
+ if (parent == null) {
+ return;
+ }
+
+ // traverse back to the head of the list of tokens before this node
+ do {
+ child = parent;
+ parent = child.getHiddenBefore();
+ } while (parent != null);
+
+ // dump that list
+ dumpHiddenTokens(child);
+ }
+
+ /**
+ * Dump the list of hidden tokens linked to from the token passed in.
+ */
+ private void dumpHiddenTokens(antlr.CommonHiddenStreamToken t) {
+ for ( ; t != null ; t=PdePreprocessor.filter.getHiddenAfter(t) ) {
+ out.print(t.getText());
+ }
+ }
+
+ /**
+ * Print the children of the given AST
+ * @param ast The AST to print
+ * @returns true iff anything was printed
+ */
+ private boolean printChildren(AST ast) throws RunnerException {
+ boolean ret = false;
+ AST child = ast.getFirstChild();
+ while (child != null) {
+ ret = true;
+ print(child);
+ child = child.getNextSibling();
+ }
+ return ret;
+ }
+
+ /**
+ * Tells whether an AST has any children or not.
+ * @return true iff the AST has at least one child
+ */
+ private boolean hasChildren(AST ast) {
+ return (ast.getFirstChild() != null);
+ }
+
+ /**
+ * Gets the best node in the subtree for printing. This really means
+ * the next node which could potentially have hiddenBefore data. It's
+ * usually the first printable leaf, but not always.
+ *
+ * @param includeThisNode Should this node be included in the search?
+ * If false, only descendants are searched.
+ *
+ * @return the first printable leaf node in an AST
+ */
+ private AST getBestPrintableNode(AST ast, boolean includeThisNode) {
+ AST child;
+
+ if (includeThisNode) {
+ child = ast;
+ } else {
+ child = ast.getFirstChild();
+ }
+
+ if (child != null) {
+
+ switch (child.getType()) {
+
+ // the following node types are printing nodes that print before
+ // any children, but then also recurse over children. So they
+ // may have hiddenBefore chains that need to be printed first. Many
+ // statements and all unary expression types qualify. Return these
+ // nodes directly
+ case CLASS_DEF:
+ case LITERAL_if:
+ case LITERAL_for:
+ case LITERAL_while:
+ case LITERAL_do:
+ case LITERAL_break:
+ case LITERAL_continue:
+ case LITERAL_return:
+ case LITERAL_switch:
+ case LITERAL_try:
+ case LITERAL_throw:
+ case LITERAL_synchronized:
+ case LITERAL_assert:
+ case BNOT:
+ case LNOT:
+ case INC:
+ case DEC:
+ case UNARY_MINUS:
+ case UNARY_PLUS:
+ return child;
+
+ // Some non-terminal node types (at the moment, I only know of
+ // MODIFIERS, but there may be other such types), can be
+ // leaves in the tree but not have any children. If this is
+ // such a node, move on to the next sibling.
+ case MODIFIERS:
+ if (child.getFirstChild() == null ) {
+ return getBestPrintableNode(child.getNextSibling(), false);
+ }
+ // new jikes doesn't like fallthrough, so just duplicated here:
+ return getBestPrintableNode(child, false);
+
+ default:
+ return getBestPrintableNode(child, false);
+ }
+ }
+
+ return ast;
+ }
+
+ /**
+ * Prints a binary operator
+ */
+ private void printBinaryOperator(AST ast) throws RunnerException {
+ print(ast.getFirstChild());
+ out.print(name(ast));
+ dumpHiddenAfter(ast);
+ print(ast.getFirstChild().getNextSibling());
+ }
+
+ /**
+ * Print the given AST. Call this function to print your PDE code.
+ *
+ * It works by making recursive calls to print children.
+ * So the code below is one big "switch" statement on the passed AST type.
+ */
+ public void print (AST ast) throws RunnerException {
+ if (ast == null) {
+ return;
+ }
+
+ AST parent = null;
+ if (!stack.isEmpty()) {
+ parent = (AST) stack.peek();
+ }
+ stack.push(ast);
+
+ AST child1 = ast.getFirstChild();
+ AST child2 = null;
+ AST child3 = null;
+ if (child1 != null) {
+ child2 = child1.getNextSibling();
+ if (child2 != null) {
+ child3 = child2.getNextSibling();
+ }
+ }
+
+ switch(ast.getType()) {
+ // The top of the tree looks like this:
+ // ROOT_ID "Whatever.java"
+ // package
+ // imports
+ // class definition
+ case ROOT_ID:
+ dumpHiddenTokens(PdePreprocessor.filter.getInitialHiddenToken());
+ printChildren(ast);
+ break;
+
+ // supporting a "package" statement in a PDE program has
+ // a bunch of issues with it that need to dealt in the compilation
+ // code too, so this isn't actually tested.
+ case PACKAGE_DEF:
+ out.print("package");
+ dumpHiddenAfter(ast);
+ print(ast.getFirstChild());
+ break;
+
+ // IMPORT has exactly one child
+ case IMPORT:
+ out.print("import");
+ dumpHiddenAfter(ast);
+ print(ast.getFirstChild());
+ break;
+
+ case CLASS_DEF:
+ case INTERFACE_DEF:
+ print(getChild(ast, MODIFIERS));
+ if (ast.getType() == CLASS_DEF) {
+ out.print("class");
+ } else {
+ out.print("interface");
+ }
+ dumpHiddenBefore(getChild(ast, IDENT));
+ print(getChild(ast, IDENT));
+ print(getChild(ast, EXTENDS_CLAUSE));
+ print(getChild(ast, IMPLEMENTS_CLAUSE));
+ print(getChild(ast, OBJBLOCK));
+ break;
+
+ case EXTENDS_CLAUSE:
+ if (hasChildren(ast)) {
+ out.print("extends");
+ dumpHiddenBefore(getBestPrintableNode(ast, false));
+ printChildren(ast);
+ }
+ break;
+
+ case IMPLEMENTS_CLAUSE:
+ if (hasChildren(ast)) {
+ out.print("implements");
+ dumpHiddenBefore(getBestPrintableNode(ast, false));
+ printChildren(ast);
+ }
+ break;
+
+ // DOT always has exactly two children.
+ case DOT:
+ print(child1);
+ out.print(".");
+ dumpHiddenAfter(ast);
+ print(child2);
+ break;
+
+ case MODIFIERS:
+ case OBJBLOCK:
+ case CTOR_DEF:
+ //case METHOD_DEF:
+ case PARAMETERS:
+ case PARAMETER_DEF:
+ case VARIABLE_DEF:
+ case TYPE:
+ case SLIST:
+ case ELIST:
+ case ARRAY_DECLARATOR:
+ case TYPECAST:
+ case EXPR:
+ case ARRAY_INIT:
+ case FOR_INIT:
+ case FOR_CONDITION:
+ case FOR_ITERATOR:
+ case METHOD_CALL:
+ case INSTANCE_INIT:
+ case INDEX_OP:
+ case SUPER_CTOR_CALL:
+ case CTOR_CALL:
+ printChildren(ast);
+ break;
+
+ case METHOD_DEF:
+ // kids seem to be: MODIFIERS TYPE setup PARAMETERS
+ //AST parent = (AST) stack.peek();
+ AST modifiersChild = ast.getFirstChild();
+ AST typeChild = modifiersChild.getNextSibling();
+ AST methodNameChild = typeChild.getNextSibling();
+ AST parametersChild = methodNameChild.getNextSibling();
+
+ // to output, use print(child) on each of the four
+
+ String methodName = methodNameChild.getText();
+ if (methodName.equals("main")) {
+ PdePreprocessor.foundMain = true;
+ }
+
+ /*
+ // 1. figure out if this is setup, draw, or loop
+ String methodName = methodNameChild.getText();
+ if (publicMethods.get(methodName) != null) {
+ // make sure this feller is public
+ boolean foundPublic = false;
+ AST child = modifiersChild.getFirstChild();
+ while (child != null) {
+ if (child.getText().equals("public")) {
+ foundPublic = true;
+ child = null;
+ } else {
+ //out.print("." + child.getText() + ".");
+ child = child.getNextSibling();
+ }
+ }
+ if (!foundPublic) {
+ out.print("public ");
+ }
+ */
+
+ // if this method doesn't have a specifier, make it public
+ // (useful for setup/keyPressed/etc)
+ boolean foundSpecifier = false;
+ AST child = modifiersChild.getFirstChild();
+ while (child != null) {
+ String childText = child.getText();
+ if (childText.equals("public") ||
+ childText.equals("protected") ||
+ childText.equals("private")) {
+ foundSpecifier = true;
+ child = null;
+ } else {
+ //out.print("." + child.getText() + ".");
+ child = child.getNextSibling();
+ }
+ }
+ if (!foundSpecifier) {
+ out.print("public ");
+ }
+ printChildren(ast); // everything is fine
+ break;
+
+ // if we have two children, it's of the form "a=0"
+ // if just one child, it's of the form "=0" (where the
+ // lhs is above this AST).
+ case ASSIGN:
+ if (child2 != null) {
+ print(child1);
+ out.print("=");
+ dumpHiddenAfter(ast);
+ print(child2);
+ }
+ else {
+ out.print("=");
+ dumpHiddenAfter(ast);
+ print(child1);
+ }
+ break;
+
+ // binary operators:
+ case PLUS:
+ case MINUS:
+ case DIV:
+ case MOD:
+ case NOT_EQUAL:
+ case EQUAL:
+ case LT:
+ case GT:
+ case LE:
+ case GE:
+ case LOR:
+ case LAND:
+ case BOR:
+ case BXOR:
+ case BAND:
+ case SL:
+ case SR:
+ case BSR:
+ case LITERAL_instanceof:
+ case PLUS_ASSIGN:
+ case MINUS_ASSIGN:
+ case STAR_ASSIGN:
+ case DIV_ASSIGN:
+ case MOD_ASSIGN:
+ case SR_ASSIGN:
+ case BSR_ASSIGN:
+ case SL_ASSIGN:
+ case BAND_ASSIGN:
+ case BXOR_ASSIGN:
+ case BOR_ASSIGN:
+ printBinaryOperator(ast);
+ break;
+
+
+ case LITERAL_for:
+ out.print(name(ast));
+ dumpHiddenAfter(ast);
+ printChildren(ast);
+ break;
+
+ case POST_INC:
+ case POST_DEC:
+ print(child1);
+ out.print(name(ast));
+ dumpHiddenAfter(ast);
+ break;
+
+ // unary operators:
+ case BNOT:
+ case LNOT:
+ case INC:
+ case DEC:
+ case UNARY_MINUS:
+ case UNARY_PLUS:
+ out.print(name(ast));
+ dumpHiddenAfter(ast);
+ print(child1);
+ break;
+
+ case LITERAL_new:
+ out.print("new");
+ dumpHiddenAfter(ast);
+ print(child1);
+ print(child2);
+ // "new String[] {...}": the stuff in {} is child3
+ if (child3 != null) {
+ print(child3);
+ }
+ break;
+
+ case LITERAL_return:
+ out.print("return");
+ dumpHiddenAfter(ast);
+ print(child1);
+ break;
+
+ case STATIC_INIT:
+ out.print("static");
+ dumpHiddenBefore(getBestPrintableNode(ast, false));
+ print(child1);
+ break;
+
+ case LITERAL_switch:
+ out.print("switch");
+ dumpHiddenAfter(ast);
+ printChildren(ast);
+ break;
+
+ case CASE_GROUP:
+ printChildren(ast);
+ break;
+
+ case LITERAL_case:
+ out.print("case");
+ dumpHiddenAfter(ast);
+ printChildren(ast);
+ break;
+
+ case LITERAL_default:
+ out.print("default");
+ dumpHiddenAfter(ast);
+ printChildren(ast);
+ break;
+
+ case NUM_INT:
+ case CHAR_LITERAL:
+ case STRING_LITERAL:
+ case NUM_FLOAT:
+ case NUM_LONG:
+ out.print(ast.getText());
+ dumpHiddenAfter(ast);
+ break;
+
+ case LITERAL_synchronized: // 0137 to fix bug #136
+ out.print(name(ast));
+ dumpHiddenAfter(ast);
+ printChildren(ast);
+ break;
+
+ case LITERAL_private:
+ case LITERAL_public:
+ case LITERAL_protected:
+ case LITERAL_static:
+ case LITERAL_transient:
+ case LITERAL_native:
+ case LITERAL_threadsafe:
+ //case LITERAL_synchronized: // 0137 to fix bug #136
+ case LITERAL_volatile:
+ case FINAL:
+ case ABSTRACT:
+ case LITERAL_package:
+ case LITERAL_void:
+ case LITERAL_boolean:
+ case LITERAL_byte:
+ case LITERAL_char:
+ case LITERAL_short:
+ case LITERAL_int:
+ case LITERAL_float:
+ case LITERAL_long:
+ case LITERAL_double:
+ case LITERAL_true:
+ case LITERAL_false:
+ case LITERAL_null:
+ case SEMI:
+ case LITERAL_this:
+ case LITERAL_super:
+ case LITERAL_continue:
+ case LITERAL_break:
+ out.print(name(ast));
+ dumpHiddenAfter(ast);
+ break;
+
+ case EMPTY_STAT:
+ case EMPTY_FIELD:
+ break;
+
+ // yuck: Distinguish between "import x.y.*" and "x = 1 * 3"
+ case STAR:
+ if (hasChildren(ast)) { // the binary mult. operator
+ printBinaryOperator(ast);
+ }
+ else { // the special "*" in import:
+ out.print("*");
+ dumpHiddenAfter(ast);
+ }
+ break;
+
+ case LITERAL_throws:
+ out.print("throws");
+ dumpHiddenAfter(ast);
+ printChildren(ast);
+ break;
+
+ case LITERAL_if:
+ out.print("if");
+ dumpHiddenAfter(ast);
+ print(child1); // the "if" condition: an EXPR
+ print(child2); // the "then" clause is an SLIST
+ if (child3 != null) {
+ out.print("else");
+ dumpHiddenBefore(getBestPrintableNode(child3, true));
+ print(child3); // optional "else" clause: an SLIST
+ }
+ break;
+
+ case LITERAL_while:
+ out.print("while");
+ dumpHiddenAfter(ast);
+ printChildren(ast);
+ break;
+
+ case LITERAL_do:
+ out.print("do");
+ dumpHiddenAfter(ast);
+ print(child1); // an SLIST
+ out.print("while");
+ dumpHiddenBefore(getBestPrintableNode(child2, false));
+ print(child2); // an EXPR
+ break;
+
+ case LITERAL_try:
+ out.print("try");
+ dumpHiddenAfter(ast);
+ printChildren(ast);
+ break;
+
+ case LITERAL_catch:
+ out.print("catch");
+ dumpHiddenAfter(ast);
+ printChildren(ast);
+ break;
+
+ // the first child is the "try" and the second is the SLIST
+ case LITERAL_finally:
+ out.print("finally");
+ dumpHiddenAfter(ast);
+ printChildren(ast);
+ break;
+
+ case LITERAL_throw:
+ out.print("throw");
+ dumpHiddenAfter(ast);
+ print(child1);
+ break;
+
+ // the dreaded trinary operator
+ case QUESTION:
+ print(child1);
+ out.print("?");
+ dumpHiddenAfter(ast);
+ print(child2);
+ print(child3);
+ break;
+
+ // pde specific or modified tokens start here
+
+ // Image -> BImage, Font -> BFont as appropriate
+ case IDENT:
+ /*
+ if (ast.getText().equals("Image") &&
+ Preferences.getBoolean("preproc.substitute_image")) { //, true)) {
+ out.print("BImage");
+ } else if (ast.getText().equals("Font") &&
+ Preferences.getBoolean("preproc.substitute_font")) { //, true)) {
+ out.print("BFont");
+ } else {
+ */
+ out.print(ast.getText());
+ //}
+ dumpHiddenAfter(ast);
+ break;
+
+ // the color datatype is just an alias for int
+ case LITERAL_color:
+ out.print("int");
+ dumpHiddenAfter(ast);
+ break;
+
+ case WEBCOLOR_LITERAL:
+ if (ast.getText().length() != 6) {
+ System.err.println("Internal error: incorrect length of webcolor " +
+ "literal should have been detected sooner.");
+ break;
+ }
+ out.print("0xff" + ast.getText());
+ dumpHiddenAfter(ast);
+ break;
+
+ // allow for stuff like int(43.2).
+ case CONSTRUCTOR_CAST:
+
+ AST nonTerminalTypeNode = child1;
+ AST terminalTypeNode = child1.getFirstChild();
+ AST exprToCast = child2;
+
+ /*
+ // if this is a string type, add .valueOf()
+ if (nonTerminalTypeNode.getType() == PdeRecognizer.TYPE &&
+ terminalTypeNode.getText().equals("String")) {
+
+ out.print(terminalTypeNode.getText() + ".valueOf");
+ dumpHiddenAfter(terminalTypeNode);
+ print(exprToCast);
+
+ // if the expresion to be cast is a string literal, try and parse it.
+ //
+ // ideally, we'd be able to do this for all expressions with a
+ // string type, not just string literals. however, the parser
+ // doesn't currently track expression type, and for full
+ // functionality, we'd need to do semantic analysis to handle
+ // imports so that we could know the return types of method calls.
+ //
+ } else if (exprToCast.getFirstChild().getType() == STRING_LITERAL ) {
+
+ switch (terminalTypeNode.getType()) {
+
+ case PdeRecognizer.LITERAL_byte:
+ out.print("Byte.parseByte");
+ dumpHiddenAfter(terminalTypeNode);
+ print(exprToCast);
+ break;
+
+ case PdeRecognizer.LITERAL_double:
+ out.print("(new Double");
+ dumpHiddenAfter(terminalTypeNode);
+ out.print(exprToCast.getFirstChild().getText() + ").doubleValue()");
+ dumpHiddenAfter(exprToCast.getFirstChild());
+ break;
+
+ case PdeRecognizer.LITERAL_float:
+ out.print("(new Float");
+ dumpHiddenAfter(terminalTypeNode);
+ out.print(exprToCast.getFirstChild().getText() + ").floatValue()");
+ dumpHiddenAfter(exprToCast.getFirstChild());
+ break;
+
+ case PdeRecognizer.LITERAL_int:
+ case PdeRecognizer.LITERAL_color:
+ out.print("Integer.parseInt");
+ dumpHiddenAfter(terminalTypeNode);
+ print(exprToCast);
+ break;
+
+ case PdeRecognizer.LITERAL_long:
+ out.print("Long.parseLong");
+ break;
+
+ case PdeRecognizer.LITERAL_short:
+ out.print("Short.parseShort");
+ break;
+
+ default:
+ throw new RunnerException(Compiler.SUPER_BADNESS);
+ }
+
+ // for builtin types, use regular casting syntax
+ } else {
+ */
+
+ // result of below is (int)(4.0
+ //out.print("(");
+ //out.print(terminalTypeNode.getText() + ")"); // typename
+ //dumpHiddenAfter(terminalTypeNode);
+ //print(exprToCast);
+ //}
+
+ //out.print("(");
+ String pooType = terminalTypeNode.getText();
+ out.print("PApplet.parse" +
+ Character.toUpperCase(pooType.charAt(0)) +
+ pooType.substring(1));
+ dumpHiddenAfter(terminalTypeNode); // the left paren
+ print(exprToCast);
+ //out.print("x)");
+
+ break;
+
+
+ // making floating point literals default to floats, not doubles
+ case NUM_DOUBLE:
+ out.print(ast.getText());
+ if (Preferences.getBoolean("preproc.substitute_floats")) { //, true) ) {
+ out.print("f");
+ }
+ dumpHiddenAfter(ast);
+ break;
+
+
+ default:
+ debug.println("Invalid type:" + ast.getType());
+ break;
+
+
+/* The following are tokens, but I don't think JavaRecognizer
+ ever produces an AST with one of these types:
+ case COMMA:
+ case LITERAL_implements:
+ case LITERAL_class:
+ case LITERAL_extends:
+ case EOF:
+ case NULL_TREE_LOOKAHEAD:
+ case BLOCK:
+ case LABELED_STAT: // refuse to implement on moral grounds :)
+ case LITERAL_import:
+ case LBRACK:
+ case RBRACK:
+ case LCURLY:
+ case RCURLY:
+ case LPAREN:
+ case RPAREN:
+ case LITERAL_else: // else is a child of "if" AST
+ case COLON: // part of the trinary operator
+ case WS: // whitespace
+ case ESC:
+ case HEX_DIGIT:
+ case VOCAB:
+
+ case EXPONENT: // exponents and float suffixes are left in the NUM_FLOAT
+ case FLOAT_SUFFIX
+*/
+ }
+
+ stack.pop();
+ }
+}
diff --git a/app/src/processing/app/preproc/PdePreprocessor.java b/app/src/processing/app/preproc/PdePreprocessor.java
new file mode 100644
index 000000000..8e70d3b90
--- /dev/null
+++ b/app/src/processing/app/preproc/PdePreprocessor.java
@@ -0,0 +1,511 @@
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+/*
+ PdePreprocessor - wrapper for default ANTLR-generated parser
+ Part of the Processing project - http://processing.org
+
+ Copyright (c) 2004-08 Ben Fry and Casey Reas
+ Copyright (c) 2001-04 Massachusetts Institute of Technology
+
+ ANTLR-generated parser and several supporting classes written
+ by Dan Mosedale via funding from the Interaction Institute IVREA.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+package processing.app.preproc;
+
+import processing.app.*;
+import processing.core.*;
+
+import java.io.*;
+import java.util.*;
+
+import antlr.*;
+import antlr.collections.*;
+
+
+/**
+ * Class that orchestrates preprocessing p5 syntax into straight Java.
+ *
+ * Current Preprocessor Subsitutions:
+ *
+ *
any function not specified as being protected or private will
+ * be made 'public'. this means that void setup() becomes
+ * public void setup(). This is important to note when
+ * coding with core.jar outside of the PDE.
+ *
compiler.substitute_floats (currently "substitute_f")
+ * treat doubles as floats, i.e. 12.3 becomes 12.3f so that people
+ * don't have to add f after their numbers all the time since it's
+ * confusing for beginners.
+ *
compiler.enhanced_casting byte(), char(), int(), float()
+ * works for casting. this is basic in the current implementation, but
+ * should be expanded as described above. color() works similarly to int(),
+ * however there is also a *function* called color(r, g, b) in p5.
+ *
compiler.color_datatype 'color' is aliased to 'int'
+ * as a datatype to represent ARGB packed into a single int, commonly
+ * used in p5 for pixels[] and other color operations. this is just a
+ * search/replace type thing, and it can be used interchangeably with int.
+ *
compiler.web_colors (currently "inline_web_colors")
+ * color c = #cc0080; should unpack to 0xffcc0080 (the ff at the top is
+ * so that the color is opaque), which is just an int.
+ *
+ * Other preprocessor functionality
+ *
+ *
detects what 'mode' the program is in: static (no function
+ * brackets at all, just assumes everything is in draw), active
+ * (setup plus draw or loop), and java mode (full java support).
+ * http://processing.org/reference/environment/
+ *
+ *
+ * The PDE Preprocessor is based on the Java Grammar that comes with
+ * ANTLR 2.7.2. Moving it forward to a new version of the grammar
+ * shouldn't be too difficult.
+ *
+ * Here's some info about the various files in this directory:
+ *
+ * java.g: this is the ANTLR grammar for Java 1.3/1.4 from the
+ * ANTLR distribution. It is in the public domain. The only change to
+ * this file from the original this file is the uncommenting of the
+ * clauses required to support assert().
+ *
+ * java.tree.g: this describes the Abstract Syntax Tree (AST)
+ * generated by java.g. It is only here as a reference for coders hacking
+ * on the preprocessor, it is not built or used at all. Note that pde.g
+ * overrides some of the java.g rules so that in PDE ASTs, there are a
+ * few minor differences. Also in the public domain.
+ *
+ * pde.g: this is the grammar and lexer for the PDE language
+ * itself. It subclasses the java.g grammar and lexer. There are a couple
+ * of overrides to java.g that I hope to convince the ANTLR folks to fold
+ * back into their grammar, but most of this file is highly specific to
+ * PDE itself.
+ * PdeEmitter.java: this class traverses the AST generated by
+ * the PDE Recognizer, and emits it as Java code, doing any necessary
+ * transformations along the way. It is based on JavaEmitter.java,
+ * available from antlr.org, written by Andy Tripp ,
+ * who has given permission for it to be distributed under the GPL.
+ *
+ * ExtendedCommonASTWithHiddenTokens.java: this adds a necessary
+ * initialize() method, as well as a number of methods to allow for XML
+ * serialization of the parse tree in a such a way that the hidden tokens
+ * are visible. Much of the code is taken from the original
+ * CommonASTWithHiddenTokens class. I hope to convince the ANTLR folks
+ * to fold these changes back into that class so that this file will be
+ * unnecessary.
+ *
+ * TokenStreamCopyingHiddenTokenFilter.java: this class provides
+ * TokenStreamHiddenTokenFilters with the concept of tokens which can be
+ * copied so that they are seen by both the hidden token stream as well
+ * as the parser itself. This is useful when one wants to use an
+ * existing parser (like the Java parser included with ANTLR) that throws
+ * away some tokens to create a parse tree which can be used to spit out
+ * a copy of the code with only minor modifications. Partially derived
+ * from ANTLR code. I hope to convince the ANTLR folks to fold this
+ * functionality back into ANTLR proper as well.
+ *
+ * whitespace_test.pde: a torture test to ensure that the
+ * preprocessor is correctly preserving whitespace, comments, and other
+ * hidden tokens correctly. See the comments in the code for details about
+ * how to run the test.
+ *
+ * All other files in this directory are generated at build time by ANTLR
+ * itself. The ANTLR manual goes into a fair amount of detail about the
+ * what each type of file is for.
+ *
+ */
+public class PdePreprocessor {
+
+ String[] defaultImports;
+
+ // these ones have the .* at the end, since a class name might be at the end
+ // instead of .* which would make trouble other classes using this can lop
+ // off the . and anything after it to produce a package name consistently.
+ //public String extraImports[];
+ ArrayList programImports;
+
+ // imports just from the code folder, treated differently
+ // than the others, since the imports are auto-generated.
+ ArrayList codeFolderImports;
+
+ static public final int STATIC = 0; // formerly BEGINNER
+ static public final int ACTIVE = 1; // formerly INTERMEDIATE
+ static public final int JAVA = 2; // formerly ADVANCED
+
+ // static to make it easier for the antlr preproc to get at it
+ static public int programType;
+ static public boolean foundMain;
+
+ String indent;
+
+ PrintStream stream;
+ Reader programReader;
+ String buildPath;
+ String name;
+
+ // used for calling the ASTFactory to get the root node
+ private static final int ROOT_ID = 0;
+
+ /**
+ * Used by PdeEmitter.dumpHiddenTokens()
+ */
+ public static TokenStreamCopyingHiddenTokenFilter filter;
+
+ static String advClassName = "";
+
+
+ /**
+ * Setup a new preprocessor.
+ */
+ public PdePreprocessor() { }
+
+
+ public int writePrefix(String program, String buildPath,
+ String name, String codeFolderPackages[]) throws FileNotFoundException {
+ this.buildPath = buildPath;
+ this.name = name;
+
+ int tabSize = Preferences.getInteger("editor.tabs.size");
+ char[] indentChars = new char[tabSize];
+ Arrays.fill(indentChars, ' ');
+ indent = new String(indentChars);
+
+ // need to reset whether or not this has a main()
+ foundMain = false;
+
+ // if the program ends with no CR or LF an OutOfMemoryError will happen.
+ // not gonna track down the bug now, so here's a hack for it:
+ // http://dev.processing.org/bugs/show_bug.cgi?id=5
+ program += "\n";
+
+ // if the program ends with an unterminated multi-line comment,
+ // an OutOfMemoryError or NullPointerException will happen.
+ // again, not gonna bother tracking this down, but here's a hack.
+ // http://dev.processing.org/bugs/show_bug.cgi?id=16
+ Sketch.scrubComments(program);
+ // this returns the scrubbed version, but more important for this
+ // function, it'll check to see if there are errors with the comments.
+
+ if (Preferences.getBoolean("preproc.substitute_unicode")) {
+ // check for non-ascii chars (these will be/must be in unicode format)
+ char p[] = program.toCharArray();
+ int unicodeCount = 0;
+ for (int i = 0; i < p.length; i++) {
+ if (p[i] > 127) unicodeCount++;
+ }
+ // if non-ascii chars are in there, convert to unicode escapes
+ if (unicodeCount != 0) {
+ // add unicodeCount * 5.. replacing each unicode char
+ // with six digit uXXXX sequence (xxxx is in hex)
+ // (except for nbsp chars which will be a replaced with a space)
+ int index = 0;
+ char p2[] = new char[p.length + unicodeCount*5];
+ for (int i = 0; i < p.length; i++) {
+ if (p[i] < 128) {
+ p2[index++] = p[i];
+
+ } else if (p[i] == 160) { // unicode for non-breaking space
+ p2[index++] = ' ';
+
+ } else {
+ int c = p[i];
+ p2[index++] = '\\';
+ p2[index++] = 'u';
+ char str[] = Integer.toHexString(c).toCharArray();
+ // add leading zeros, so that the length is 4
+ //for (int i = 0; i < 4 - str.length; i++) p2[index++] = '0';
+ for (int m = 0; m < 4 - str.length; m++) p2[index++] = '0';
+ System.arraycopy(str, 0, p2, index, str.length);
+ index += str.length;
+ }
+ }
+ program = new String(p2, 0, index);
+ }
+ }
+
+ // These may change in-between (if the prefs panel adds this option)
+ // so grab them here on construction.
+ String prefsLine = Preferences.get("preproc.imports");
+ defaultImports = PApplet.splitTokens(prefsLine, ", ");
+
+ //String importRegexp = "(?:^|\\s|;)(import\\s+)(\\S+)(\\s*;)";
+ String importRegexp = "(?:^|;)\\s*(import\\s+)(\\S+)(\\s*;)";
+ programImports = new ArrayList();
+
+ do {
+ String[] pieces = PApplet.match(program, importRegexp);
+ // Stop the loop if we've removed all the importy lines
+ if (pieces == null) break;
+
+ String piece = pieces[1] + pieces[2] + pieces[3];
+ int len = piece.length(); // how much to trim out
+
+ programImports.add(pieces[2]); // the package name
+ int idx = program.indexOf(piece);
+ // just remove altogether?
+ program = program.substring(0, idx) + program.substring(idx + len);
+
+ } while (true);
+
+ codeFolderImports = new ArrayList();
+ if (codeFolderPackages != null) {
+ for (String item : codeFolderPackages) {
+ codeFolderImports.add(item + ".*");
+ }
+ }
+ // do this after the program gets re-combobulated
+ this.programReader = new StringReader(program);
+
+ File streamFile = new File(buildPath, name + ".java");
+ stream = new PrintStream(new FileOutputStream(streamFile));
+ int importsLength = writeImports(stream);
+
+ // return the length of the imports plus the extra lines for declarations
+ return importsLength + 2;
+ }
+
+
+ /**
+ * preprocesses a pde file and write out a java file
+ * @return the classname of the exported Java
+ */
+ //public String write(String program, String buildPath, String name,
+ // String extraImports[]) throws java.lang.Exception {
+ public String write() throws java.lang.Exception {
+ // create a lexer with the stream reader, and tell it to handle
+ // hidden tokens (eg whitespace, comments) since we want to pass these
+ // through so that the line numbers when the compiler reports errors
+ // match those that will be highlighted in the PDE IDE
+ //
+ PdeLexer lexer = new PdeLexer(programReader);
+ lexer.setTokenObjectClass("antlr.CommonHiddenStreamToken");
+
+ // create the filter for hidden tokens and specify which tokens to
+ // hide and which to copy to the hidden text
+ //
+ filter = new TokenStreamCopyingHiddenTokenFilter(lexer);
+ filter.hide(PdeRecognizer.SL_COMMENT);
+ filter.hide(PdeRecognizer.ML_COMMENT);
+ filter.hide(PdeRecognizer.WS);
+ filter.copy(PdeRecognizer.SEMI);
+ filter.copy(PdeRecognizer.LPAREN);
+ filter.copy(PdeRecognizer.RPAREN);
+ filter.copy(PdeRecognizer.LCURLY);
+ filter.copy(PdeRecognizer.RCURLY);
+ filter.copy(PdeRecognizer.COMMA);
+ filter.copy(PdeRecognizer.RBRACK);
+ filter.copy(PdeRecognizer.LBRACK);
+ filter.copy(PdeRecognizer.COLON);
+
+ // create a parser and set what sort of AST should be generated
+ //
+ PdeRecognizer parser = new PdeRecognizer(filter);
+
+ // use our extended AST class
+ //
+ parser.setASTNodeClass("antlr.ExtendedCommonASTWithHiddenTokens");
+
+ // start parsing at the compilationUnit non-terminal
+ //
+ parser.pdeProgram();
+
+ // set up the AST for traversal by PdeEmitter
+ //
+ ASTFactory factory = new ASTFactory();
+ AST parserAST = parser.getAST();
+ AST rootNode = factory.create(ROOT_ID, "AST ROOT");
+ rootNode.setFirstChild(parserAST);
+
+ // unclear if this actually works, but it's worth a shot
+ //
+ //((CommonAST)parserAST).setVerboseStringConversion(
+ // true, parser.getTokenNames());
+ // (made to use the static version because of jikes 1.22 warning)
+ CommonAST.setVerboseStringConversion(true, parser.getTokenNames());
+
+ // if this is an advanced program, the classname is already defined.
+ //
+ if (programType == JAVA) {
+ name = getFirstClassName(parserAST);
+ }
+
+ // if 'null' was passed in for the name, but this isn't
+ // a 'java' mode class, then there's a problem, so punt.
+ //
+ if (name == null) return null;
+
+ // output the code
+ //
+ PdeEmitter emitter = new PdeEmitter();
+ //writeHeader(stream, extraImports, name);
+ writeDeclaration(stream, name);
+
+ emitter.setOut(stream);
+ emitter.print(rootNode);
+
+ writeFooter(stream, name);
+ stream.close();
+
+ // if desired, serialize the parse tree to an XML file. can
+ // be viewed usefully with Mozilla or IE
+
+ if (Preferences.getBoolean("preproc.output_parse_tree")) {
+ writeParseTree("parseTree.xml", parserAST);
+ }
+
+ return name;
+ }
+
+
+ protected void writeParseTree(String filename, AST ast) {
+ try {
+ PrintStream stream = new PrintStream(new FileOutputStream(filename));
+ stream.println("");
+ stream.println("");
+ OutputStreamWriter writer = new OutputStreamWriter(stream);
+ if (ast != null) {
+ ((CommonAST) ast).xmlSerialize(writer);
+ }
+ writer.flush();
+ stream.println("");
+ writer.close();
+ } catch (IOException e) {
+
+ }
+ }
+
+ int writeImports(PrintStream out) {
+ out.println("import processing.core.*; ");
+ out.println("import processing.xml.*; ");
+ out.println();
+ int count = 3;
+
+ if (programImports.size() != 0) {
+ for (String item : programImports) {
+ out.println("import " + item + "; ");
+ }
+ out.println();
+ count += programImports.size() + 1;
+ }
+
+ if (codeFolderImports.size() != 0) {
+ for (String item : codeFolderImports) {
+ out.println("import " + item + "; ");
+ }
+ out.println();
+ count += codeFolderImports.size() + 1;
+ }
+
+ for (String item : defaultImports) {
+ out.println("import " + item + ".*; ");
+ }
+ out.println();
+ count += defaultImports.length + 1;
+
+ return count;
+ }
+
+
+ /**
+ * Write any required header material (eg imports, class decl stuff)
+ *
+ * @param out PrintStream to write it to.
+ * @param exporting Is this being exported from PDE?
+ * @param name Name of the class being created.
+ */
+ void writeDeclaration(PrintStream out, String className) {
+
+ String indent = " ";
+
+ if (programType == JAVA) {
+ // Print two blank lines so that the offset doesn't change
+ out.println();
+ out.println();
+
+ } else if (programType == ACTIVE) {
+ // Print an extra blank line so the offset is identical to the others
+ out.println("public class " + className + " extends PApplet {");
+ out.println();
+
+ } else if (programType == STATIC) {
+ out.println("public class " + className + " extends PApplet {");
+ out.print(indent + "public void setup() {");
+ }
+ }
+
+ /**
+ * Write any necessary closing text.
+ *
+ * @param out PrintStream to write it to.
+ */
+ void writeFooter(PrintStream out, String className) {
+
+ if (programType == STATIC) {
+ // close off draw() definition
+ out.println(indent + "noLoop();");
+ out.println("} ");
+ }
+
+ if ((programType == STATIC) || (programType == ACTIVE)) {
+ if (!PdePreprocessor.foundMain) {
+ out.println(indent + "static public void main(String args[]) {");
+ out.print(indent + indent + "PApplet.main(new String[] { ");
+
+ if (Preferences.getBoolean("export.application.fullscreen")) {
+ out.print("\"" + PApplet.ARGS_PRESENT + "\", ");
+
+ String farbe = Preferences.get("run.present.bgcolor");
+ out.print("\"" + PApplet.ARGS_BGCOLOR + "=" + farbe + "\", ");
+
+ if (Preferences.getBoolean("export.application.stop")) {
+ farbe = Preferences.get("run.present.stop.color");
+ out.print("\"" + PApplet.ARGS_STOP_COLOR + "=" + farbe + "\", ");
+ } else {
+ out.print("\"" + PApplet.ARGS_HIDE_STOP + "\", ");
+ }
+ } else {
+ String farbe = Preferences.get("run.window.bgcolor");
+ out.print("\"" + PApplet.ARGS_BGCOLOR + "=" + farbe + "\", ");
+ }
+ out.println("\"" + className + "\" });");
+ out.println(indent + "}");
+ }
+
+ // close off the class definition
+ out.println("}");
+ }
+ }
+
+
+ public ArrayList getExtraImports() {
+ return programImports;
+ }
+
+
+ /**
+ * Find the first CLASS_DEF node in the tree, and return the name of the
+ * class in question.
+ *
+ * TODO [dmose] right now, we're using a little hack to the grammar to get
+ * this info. In fact, we should be descending the AST passed in.
+ */
+ String getFirstClassName(AST ast) {
+
+ String t = advClassName;
+ advClassName = "";
+
+ return t;
+ }
+}
diff --git a/app/src/processing/app/preproc/clean.sh b/app/src/processing/app/preproc/clean.sh
new file mode 100755
index 000000000..a3db270b2
--- /dev/null
+++ b/app/src/processing/app/preproc/clean.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+rm -f *Lexer.java
+rm -f *Recognizer.java
+rm -f *TokenTypes.java
+rm -f *TokenTypes.txt
+rm -f *TreeParser.java
+rm -f *TreeParserTokenTypes.java
+rm -f *TreeParserTokenTypes.txt
+rm -f expanded*.g
+
diff --git a/app/src/processing/app/preproc/make.sh b/app/src/processing/app/preproc/make.sh
new file mode 100755
index 000000000..90324ddc9
--- /dev/null
+++ b/app/src/processing/app/preproc/make.sh
@@ -0,0 +1,3 @@
+java -cp ../../build/macosx/work/lib/antlr.jar antlr.Tool java.g
+# now build the pde stuff that extends the java classes
+java -cp ../../build/macosx/work/lib/antlr.jar antlr.Tool -glib java.g pde.g
\ No newline at end of file
diff --git a/app/src/processing/app/preproc/pde.g b/app/src/processing/app/preproc/pde.g
new file mode 100644
index 000000000..fced570d4
--- /dev/null
+++ b/app/src/processing/app/preproc/pde.g
@@ -0,0 +1,304 @@
+/* -*- mode: antlr; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+header {
+package processing.app.preproc;
+
+import processing.app.*;
+}
+
+class PdeRecognizer extends JavaRecognizer;
+
+options {
+ importVocab = Java;
+ exportVocab = PdePartial;
+
+ codeGenMakeSwitchThreshold=10; // this is set high for debugging
+ codeGenBitsetTestThreshold=10; // this is set high for debugging
+
+ // developers may to want to set this to true for better
+ // debugging messages, however, doing so disables highlighting errors
+ // in the editor.
+ defaultErrorHandler = false; //true;
+}
+
+tokens {
+ CONSTRUCTOR_CAST; EMPTY_FIELD;
+}
+
+pdeProgram
+ // only java mode programs will have their own public classes or
+ // imports (and they must have at least one)
+ : ( "public" "class" | "import" ) => javaProgram
+ { PdePreprocessor.programType = PdePreprocessor.JAVA; }
+
+ // the syntactic predicate here looks for any minimal (thus
+ // the non-greedy qualifier) number of fields, followed by
+ // the tokens that represent the definition of loop() or
+ // some other member function. java mode programs may have such
+ // definitions, but they won't reach this point, having already been
+ // selected in the previous alternative. static mode programs
+ // don't have member functions.
+ //
+ | ( ( options {greedy=false;}: possiblyEmptyField)* "void" IDENT LPAREN )
+ => activeProgram
+ { PdePreprocessor.programType = PdePreprocessor.ACTIVE; }
+
+ | staticProgram
+ { PdePreprocessor.programType = PdePreprocessor.STATIC; }
+ ;
+
+// advanced mode is really just a normal java file
+javaProgram
+ : compilationUnit
+ ;
+
+activeProgram
+ : (possiblyEmptyField)+
+ ;
+
+staticProgram
+ : (statement)*
+ ;
+
+// copy of the java.g rule with WEBCOLOR_LITERAL added
+constant
+ : NUM_INT
+ | CHAR_LITERAL
+ | STRING_LITERAL
+ | NUM_FLOAT
+ | NUM_LONG
+ | NUM_DOUBLE
+ | webcolor_literal
+ ;
+
+// of the form #cc008f in PDE
+webcolor_literal
+ : w:WEBCOLOR_LITERAL
+ { Preferences.getBoolean("preproc.web_colors") &&
+ w.getText().length() == 6 }? // must be exactly 6 hex digits
+ ;
+
+// copy of the java.g builtInType rule
+builtInConsCastType
+ : "void"
+ | "boolean"
+ | "byte"
+ | "char"
+ | "short"
+ | "int"
+ | "float"
+ | "long"
+ | "double"
+ ;
+
+// our types include the java types and "color". this is separated into two
+// rules so that constructor casts can just use the original typelist, since
+// we don't want to support the color type as a constructor cast.
+//
+builtInType
+ : builtInConsCastType
+ | "color" // aliased to an int in PDE
+ { Preferences.getBoolean("preproc.color_datatype") }?
+ ;
+
+// constructor style casts.
+constructorCast!
+ : t:consCastTypeSpec[true]
+ LPAREN!
+ e:expression
+ RPAREN!
+ // if this is a string literal, make sure the type we're trying to cast
+ // to is one of the supported ones
+ //
+ { #e.getType() != STRING_LITERAL ||
+ ( #t.getType() == LITERAL_byte ||
+ #t.getType() == LITERAL_double ||
+ #t.getType() == LITERAL_float ||
+ #t.getType() == LITERAL_int ||
+ #t.getType() == LITERAL_long ||
+ #t.getType() == LITERAL_short ) }?
+ // create the node
+ //
+ {#constructorCast = #(#[CONSTRUCTOR_CAST,"CONSTRUCTOR_CAST"], t, e);}
+ ;
+
+// A list of types that be used as the destination type in a constructor-style
+// cast. Ideally, this would include all class types, not just "String".
+// Unfortunately, it's not possible to tell whether Foo(5) is supposed to be
+// a method call or a constructor cast without have a table of all valid
+// types or methods, which requires semantic analysis (eg processing of import
+// statements). So we accept the set of built-in types plus "String".
+//
+consCastTypeSpec[boolean addImagNode]
+// : stringTypeSpec[addImagNode]
+// | builtInConsCastTypeSpec[addImagNode]
+ : builtInConsCastTypeSpec[addImagNode]
+// trying to remove String() cast [fry]
+ ;
+
+//stringTypeSpec[boolean addImagNode]
+// : id:IDENT { #id.getText().equals("String") }?
+// {
+// if ( addImagNode ) {
+// #stringTypeSpec = #(#[TYPE,"TYPE"],
+// #stringTypeSpec);
+// }
+// }
+// ;
+
+builtInConsCastTypeSpec[boolean addImagNode]
+ : builtInConsCastType
+ {
+ if ( addImagNode ) {
+ #builtInConsCastTypeSpec = #(#[TYPE,"TYPE"],
+ #builtInConsCastTypeSpec);
+ }
+ }
+ ;
+
+// Since "color" tokens are lexed as LITERAL_color now, we need to have a rule
+// that can generate a method call from an expression that starts with this
+// token
+//
+colorMethodCall
+ : c:"color" {#c.setType(IDENT);} // this would default to LITERAL_color
+ lp:LPAREN^ {#lp.setType(METHOD_CALL);}
+ argList
+ RPAREN!
+ ;
+
+// copy of the java.g rule with added constructorCast and colorMethodCall
+// alternatives
+primaryExpression
+ : (consCastTypeSpec[false] LPAREN) => constructorCast
+ { Preferences.getBoolean("preproc.enhanced_casting") }?
+ | identPrimary ( options {greedy=true;} : DOT^ "class" )?
+ | constant
+ | "true"
+ | "false"
+ | "null"
+ | newExpression
+ | "this"
+ | "super"
+ | LPAREN! assignmentExpression RPAREN!
+ | colorMethodCall
+ // look for int.class and int[].class
+ | builtInType
+ ( lbt:LBRACK^ {#lbt.setType(ARRAY_DECLARATOR);} RBRACK! )*
+ DOT^ "class"
+ ;
+
+// the below variable rule hacks are needed so that it's possible for the
+// emitter to correctly output variable declarations of the form "float a, b"
+// from the AST. This means that our AST has a somewhat different form in
+// these rules than the java one does, and this new form may have its own
+// semantic issues. But it seems to fix the comma declaration issues.
+//
+variableDefinitions![AST mods, AST t]
+ : vd:variableDeclarator[getASTFactory().dupTree(mods),
+ getASTFactory().dupTree(t)]
+ {#variableDefinitions = #(#[VARIABLE_DEF,"VARIABLE_DEF"], mods,
+ t, vd);}
+ ;
+variableDeclarator[AST mods, AST t]
+ : ( id:IDENT (lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK!)*
+ v:varInitializer (COMMA!)? )+
+ ;
+
+// java.g builds syntax trees with an inconsistent structure. override one of
+// the rules there to fix this.
+//
+explicitConstructorInvocation!
+ : t:"this" LPAREN a1:argList RPAREN SEMI
+ {#explicitConstructorInvocation = #(#[CTOR_CALL, "CTOR_CALL"],
+ #t, #a1);}
+ | s:"super" LPAREN a2:argList RPAREN SEMI
+ {#explicitConstructorInvocation = #(#[SUPER_CTOR_CALL,
+ "SUPER_CTOR_CALL"],
+ #s, #a2);}
+ ;
+
+// quick-n-dirty hack to the get the advanced class name. we should
+// really be getting it from the AST and not forking this rule from
+// the java.g copy at all. Since this is a recursive descent parser, we get
+// the last class name in the file so that we don't end up with the classname
+// of an inner class. If there is more than one "outer" class in a file,
+// this heuristic will fail.
+//
+classDefinition![AST modifiers]
+ : "class" i:IDENT
+ // it _might_ have a superclass...
+ sc:superClassClause
+ // it might implement some interfaces...
+ ic:implementsClause
+ // now parse the body of the class
+ cb:classBlock
+ {#classDefinition = #(#[CLASS_DEF,"CLASS_DEF"],
+ modifiers,i,sc,ic,cb);
+ PdePreprocessor.advClassName = i.getText();}
+ ;
+
+possiblyEmptyField
+ : field
+ | s:SEMI {#s.setType(EMPTY_FIELD);}
+ ;
+
+class PdeLexer extends JavaLexer;
+
+options {
+ importVocab=PdePartial;
+ exportVocab=Pde;
+}
+
+// We need to preserve whitespace and commentary instead of ignoring
+// like the supergrammar does. Otherwise Jikes won't be able to give
+// us error messages that point to the equivalent PDE code.
+
+// WS, SL_COMMENT, ML_COMMENT are copies of the original productions,
+// but with the SKIP assigment removed.
+
+WS : ( ' '
+ | '\t'
+ | '\f'
+ // handle newlines
+ | ( options {generateAmbigWarnings=false;}
+ : "\r\n" // Evil DOS
+ | '\r' // Macintosh
+ | '\n' // Unix (the right way)
+ )
+ { newline(); }
+ )+
+ ;
+
+// Single-line comments
+SL_COMMENT
+ : "//"
+ (~('\n'|'\r'))* ('\n'|'\r'('\n')?)
+ {newline();}
+ ;
+
+// multiple-line comments
+ML_COMMENT
+ : "/*"
+ ( /* '\r' '\n' can be matched in one alternative or by matching
+ '\r' in one iteration and '\n' in another. I am trying to
+ handle any flavor of newline that comes in, but the language
+ that allows both "\r\n" and "\r" and "\n" to all be valid
+ newline is ambiguous. Consequently, the resulting grammar
+ must be ambiguous. I'm shutting this warning off.
+ */
+ options {
+ generateAmbigWarnings=false;
+ }
+ :
+ { LA(2)!='/' }? '*'
+ | '\r' '\n' {newline();}
+ | '\r' {newline();}
+ | '\n' {newline();}
+ | ~('*'|'\n'|'\r')
+ )*
+ "*/"
+ ;
+
+WEBCOLOR_LITERAL
+ : '#'! (HEX_DIGIT)+
+ ;
diff --git a/app/src/processing/app/preproc/whitespace_test.pde b/app/src/processing/app/preproc/whitespace_test.pde
new file mode 100644
index 000000000..290872db6
--- /dev/null
+++ b/app/src/processing/app/preproc/whitespace_test.pde
@@ -0,0 +1,150 @@
+// this is a whitespace and other invisible token torture test for the ANTLR-based
+// preprocessor. edit pde.properties and set "editor.save_build_files" to true.
+// then, build this in processing. next, use
+//
+// diff -u --strip-trailing-cr \
+// work/sketchbook/default/whitespace_test/whitespace_test.pde \
+// work/lib/build/MyDemo.java
+//
+// to compare the files before and after preprocessing. There should not be
+// any differences.
+
+import // comment test
+ java.io.*;
+
+// comment 1
+public class // post-class comment
+
+// comment2
+
+MyDemo extends BApplet implements // foo
+ java.lang. // bar
+ Cloneable {
+
+ //argh
+
+ public // foo
+ String // bar
+ fff = /*rheet */ "stuff";
+
+ static /*a*/ {
+ /*foo*/
+ /*bar*/
+ six = 6;
+ } /* b*/
+
+ static /*a*/ final /*b*/ int six;
+
+ void setup()
+ {
+ size(200, 200);
+ background(255);
+
+ this . fff = /* ook */ (String)/*foo*/"yo";
+ rectMode(CENTER_DIAMETER); // comment 1a
+ noStroke();
+ fill(255, 204, 0);
+
+ int q = /*a*/ - /*b*/ 1;
+
+ boolean c = /*a*/ ! /*b*/ true;
+ }
+
+ int foo() /*a*/ throws /*b*/ java.lang.Exception /*c*/
+ {
+ int b = 7;
+ switch /*a*/ ( /*b*/ b /*c*/ ) {
+ case /*d*/ 1 /*e*/: /*f*/
+ int c=9;
+ /*g*/
+ break; /*h*/
+ default /*i*/ :
+ int d=9;
+ break;
+ }
+
+ try { /* qq */
+ loop(); /* rr */
+ } catch /*ss*/ (java.lang.Exception ex) /*tt*/ {
+ b = 8; /*tut*/
+ throw /*utu*/ ex;
+ } /*uu*/ finally /*vv*/ {
+ b = 9;
+ } /*ww*/
+
+ b /*aaa*/ = /*bbb*/ true /*ccc*/ ? /*ddd*/ 0 /*eee*/
+ : /* fff*/ 1 /*ggg*/;
+ return /*a*/ 5 /*b*/;
+ }
+
+ // comment 2
+ void loop()
+ {
+
+ int arr1 /* VVV */ [ /* XXX */] /*YYY*/ ;
+ int[] arr2 = { /*a*/ 2, 3 /*b*/ } /*c*/ ;
+
+ for /*a*/ (/*b*/ int j=0 /*c*/; /*d*/ j<2/*e*/ ; /*f*/ j++ /*g*/)
+ /*h*/
+ arr2[1] = 6;
+
+ /*foo*/
+ ;
+ /*bar*/
+ rect(width-mouseX, height-mouseY, 50, 50);
+ rect(mouseX, mouseY, 50, 50);
+
+ if (/*a*/ arr2[1] == 6/*b*/) {
+ /*c*/
+ int d=7;
+ } /*d*/else /*e*/{
+ int e=8;
+ /*f*/
+ }
+
+ int f;
+ if (/*aa*/ arr2[1] ==6 /*bb*/ )
+ /*cc*/
+ f=8; /*dd*/
+ else /*ee*/
+ f=10; /*ff*/
+
+ while ( /*aaa*/ f < 15) /*bbb*/ {
+ f ++;
+ } /*ggg*/
+
+ do /* aaaa */ {
+ f++;
+ } /*bbbb*/ while /*cccc*/ ( /*a*/ - /*b*/ 20 > f) /*dddd*/;
+
+ f = 2 * 3 + 4;
+
+ f = ( 2 * 3 ) + 4 + /*aa*/ -/*bb*/1;
+
+ f = 2 * ( 3 + 4 ) ;
+
+ fff = /*a*/ new /*b*/ String(/*c*/"foo"/*d*/) /*e*/;
+
+ int arr3[] = /*a*/ new /*b*/ int/*c*/[/*d*/] /*e*/ {1/*f*/,2};
+ int arr4[][] = new /*a*/int/*b*/[1][2]/*c*/;
+
+ }
+
+ class Shoe
+ {
+ Shoe(String brand)
+ {
+ println(brand);
+ }
+ }
+
+ class NikeAir extends Shoe
+ {
+ NikeAir()
+ {
+ /*a*/ super /*b*/ ( /*c*/ "Nike" /*d*/ ) /*e*/ ;
+
+ /*aa*/ ( /*bb*/ new /*cc*/ MyDemo /*dd*/ (/*ee*/)/*ff*/)/*gg*/./*hh*/super/*ii*/(/*jj*/5/*kk*/);
+ }
+ }
+}
diff --git a/app/src/processing/app/syntax/CTokenMarker.java b/app/src/processing/app/syntax/CTokenMarker.java
new file mode 100644
index 000000000..1fdb33fe6
--- /dev/null
+++ b/app/src/processing/app/syntax/CTokenMarker.java
@@ -0,0 +1,274 @@
+/*
+ * CTokenMarker.java - C token marker
+ * Copyright (C) 1998, 1999 Slava Pestov
+ *
+ * You may use and modify this package for any purpose. Redistribution is
+ * permitted, in both source and binary form, provided that this notice
+ * remains intact in all source distributions of this package.
+ */
+
+package processing.app.syntax;
+
+import javax.swing.text.Segment;
+
+/**
+ * C token marker.
+ *
+ * @author Slava Pestov
+ * @version $Id: CTokenMarker.java 1268 2005-04-09 02:30:37Z benfry $
+ */
+public class CTokenMarker extends TokenMarker
+{
+ public CTokenMarker()
+ {
+ this(true,getKeywords());
+ }
+
+ public CTokenMarker(boolean cpp, KeywordMap keywords)
+ {
+ this.cpp = cpp;
+ this.keywords = keywords;
+ }
+
+ public byte markTokensImpl(byte token, Segment line, int lineIndex)
+ {
+ char[] array = line.array;
+ int offset = line.offset;
+ lastOffset = offset;
+ lastKeyword = offset;
+ int mlength = line.count + offset;
+ boolean backslash = false;
+
+loop: for(int i = offset; i < mlength; i++)
+ {
+ int i1 = (i+1);
+
+ char c = array[i];
+ if(c == '\\')
+ {
+ backslash = !backslash;
+ continue;
+ }
+
+ switch(token)
+ {
+ case Token.NULL:
+ switch(c)
+ {
+ case '#':
+ if(backslash)
+ backslash = false;
+ else if(cpp)
+ {
+ if(doKeyword(line,i,c))
+ break;
+ addToken(i - lastOffset,token);
+ addToken(mlength - i,Token.KEYWORD2);
+ lastOffset = lastKeyword = mlength;
+ break loop;
+ }
+ break;
+ case '"':
+ doKeyword(line,i,c);
+ if(backslash)
+ backslash = false;
+ else
+ {
+ addToken(i - lastOffset,token);
+ token = Token.LITERAL1;
+ lastOffset = lastKeyword = i;
+ }
+ break;
+ case '\'':
+ doKeyword(line,i,c);
+ if(backslash)
+ backslash = false;
+ else
+ {
+ addToken(i - lastOffset,token);
+ token = Token.LITERAL2;
+ lastOffset = lastKeyword = i;
+ }
+ break;
+ case ':':
+ if(lastKeyword == offset)
+ {
+ if(doKeyword(line,i,c))
+ break;
+ backslash = false;
+ addToken(i1 - lastOffset,Token.LABEL);
+ lastOffset = lastKeyword = i1;
+ }
+ else if(doKeyword(line,i,c))
+ break;
+ break;
+ case '/':
+ backslash = false;
+ doKeyword(line,i,c);
+ if(mlength - i > 1)
+ {
+ switch(array[i1])
+ {
+ case '*':
+ addToken(i - lastOffset,token);
+ lastOffset = lastKeyword = i;
+ if(mlength - i > 2 && array[i+2] == '*')
+ token = Token.COMMENT2;
+ else
+ token = Token.COMMENT1;
+ break;
+ case '/':
+ addToken(i - lastOffset,token);
+ addToken(mlength - i,Token.COMMENT1);
+ lastOffset = lastKeyword = mlength;
+ break loop;
+ }
+ }
+ break;
+ default:
+ backslash = false;
+ if(!Character.isLetterOrDigit(c)
+ && c != '_')
+ doKeyword(line,i,c);
+ break;
+ }
+ break;
+ case Token.COMMENT1:
+ case Token.COMMENT2:
+ backslash = false;
+ if(c == '*' && mlength - i > 1)
+ {
+ if(array[i1] == '/')
+ {
+ i++;
+ addToken((i+1) - lastOffset,token);
+ token = Token.NULL;
+ lastOffset = lastKeyword = i+1;
+ }
+ }
+ break;
+ case Token.LITERAL1:
+ if(backslash)
+ backslash = false;
+ else if(c == '"')
+ {
+ addToken(i1 - lastOffset,token);
+ token = Token.NULL;
+ lastOffset = lastKeyword = i1;
+ }
+ break;
+ case Token.LITERAL2:
+ if(backslash)
+ backslash = false;
+ else if(c == '\'')
+ {
+ addToken(i1 - lastOffset,Token.LITERAL1);
+ token = Token.NULL;
+ lastOffset = lastKeyword = i1;
+ }
+ break;
+ default:
+ throw new InternalError("Invalid state: "
+ + token);
+ }
+ }
+
+ if(token == Token.NULL)
+ doKeyword(line,mlength,'\0');
+
+ switch(token)
+ {
+ case Token.LITERAL1:
+ case Token.LITERAL2:
+ addToken(mlength - lastOffset,Token.INVALID);
+ token = Token.NULL;
+ break;
+ case Token.KEYWORD2:
+ addToken(mlength - lastOffset,token);
+ if (!backslash) token = Token.NULL;
+ addToken(mlength - lastOffset,token);
+ break;
+ default:
+ addToken(mlength - lastOffset,token);
+ break;
+ }
+
+ return token;
+ }
+
+ public static KeywordMap getKeywords()
+ {
+ if(cKeywords == null)
+ {
+ cKeywords = new KeywordMap(false);
+ cKeywords.add("char",Token.KEYWORD3);
+ cKeywords.add("double",Token.KEYWORD3);
+ cKeywords.add("enum",Token.KEYWORD3);
+ cKeywords.add("float",Token.KEYWORD3);
+ cKeywords.add("int",Token.KEYWORD3);
+ cKeywords.add("long",Token.KEYWORD3);
+ cKeywords.add("short",Token.KEYWORD3);
+ cKeywords.add("signed",Token.KEYWORD3);
+ cKeywords.add("struct",Token.KEYWORD3);
+ cKeywords.add("typedef",Token.KEYWORD3);
+ cKeywords.add("union",Token.KEYWORD3);
+ cKeywords.add("unsigned",Token.KEYWORD3);
+ cKeywords.add("void",Token.KEYWORD3);
+ cKeywords.add("auto",Token.KEYWORD1);
+ cKeywords.add("const",Token.KEYWORD1);
+ cKeywords.add("extern",Token.KEYWORD1);
+ cKeywords.add("register",Token.KEYWORD1);
+ cKeywords.add("static",Token.KEYWORD1);
+ cKeywords.add("volatile",Token.KEYWORD1);
+ cKeywords.add("break",Token.KEYWORD1);
+ cKeywords.add("case",Token.KEYWORD1);
+ cKeywords.add("continue",Token.KEYWORD1);
+ cKeywords.add("default",Token.KEYWORD1);
+ cKeywords.add("do",Token.KEYWORD1);
+ cKeywords.add("else",Token.KEYWORD1);
+ cKeywords.add("for",Token.KEYWORD1);
+ cKeywords.add("goto",Token.KEYWORD1);
+ cKeywords.add("if",Token.KEYWORD1);
+ cKeywords.add("return",Token.KEYWORD1);
+ cKeywords.add("sizeof",Token.KEYWORD1);
+ cKeywords.add("switch",Token.KEYWORD1);
+ cKeywords.add("while",Token.KEYWORD1);
+ cKeywords.add("asm",Token.KEYWORD2);
+ cKeywords.add("asmlinkage",Token.KEYWORD2);
+ cKeywords.add("far",Token.KEYWORD2);
+ cKeywords.add("huge",Token.KEYWORD2);
+ cKeywords.add("inline",Token.KEYWORD2);
+ cKeywords.add("near",Token.KEYWORD2);
+ cKeywords.add("pascal",Token.KEYWORD2);
+ cKeywords.add("true",Token.LITERAL2);
+ cKeywords.add("false",Token.LITERAL2);
+ cKeywords.add("NULL",Token.LITERAL2);
+ }
+ return cKeywords;
+ }
+
+ // private members
+ private static KeywordMap cKeywords;
+
+ private boolean cpp;
+ private KeywordMap keywords;
+ private int lastOffset;
+ private int lastKeyword;
+
+ private boolean doKeyword(Segment line, int i, char c)
+ {
+ int i1 = i+1;
+
+ int len = i - lastKeyword;
+ byte id = keywords.lookup(line,lastKeyword,len);
+ if(id != Token.NULL)
+ {
+ if(lastKeyword != lastOffset)
+ addToken(lastKeyword - lastOffset,Token.NULL);
+ addToken(len,id);
+ lastOffset = i;
+ }
+ lastKeyword = i1;
+ return false;
+ }
+}
diff --git a/app/src/processing/app/syntax/DefaultInputHandler.java b/app/src/processing/app/syntax/DefaultInputHandler.java
new file mode 100644
index 000000000..9814cf252
--- /dev/null
+++ b/app/src/processing/app/syntax/DefaultInputHandler.java
@@ -0,0 +1,374 @@
+/*
+ * DefaultInputHandler.java - Default implementation of an input handler
+ * Copyright (C) 1999 Slava Pestov
+ *
+ * You may use and modify this package for any purpose. Redistribution is
+ * permitted, in both source and binary form, provided that this notice
+ * remains intact in all source distributions of this package.
+ */
+
+package processing.app.syntax;
+
+import javax.swing.KeyStroke;
+import java.awt.event.*;
+import java.awt.Toolkit;
+import java.util.Hashtable;
+import java.util.StringTokenizer;
+
+/**
+ * The default input handler. It maps sequences of keystrokes into actions
+ * and inserts key typed events into the text area.
+ * @author Slava Pestov
+ * @version $Id: DefaultInputHandler.java 1438 2005-05-11 08:34:16Z benfry $
+ */
+public class DefaultInputHandler extends InputHandler
+{
+ /**
+ * Creates a new input handler with no key bindings defined.
+ */
+ public DefaultInputHandler()
+ {
+ bindings = currentBindings = new Hashtable();
+ }
+
+ /**
+ * Sets up the default key bindings.
+ */
+ public void addDefaultKeyBindings()
+ {
+ addKeyBinding("BACK_SPACE",BACKSPACE);
+ addKeyBinding("C+BACK_SPACE",BACKSPACE_WORD);
+ addKeyBinding("DELETE",DELETE);
+ addKeyBinding("C+DELETE",DELETE_WORD);
+
+ addKeyBinding("ENTER",INSERT_BREAK);
+ addKeyBinding("TAB",INSERT_TAB);
+
+ addKeyBinding("INSERT",OVERWRITE);
+ addKeyBinding("C+\\",TOGGLE_RECT);
+
+ addKeyBinding("HOME",HOME);
+ addKeyBinding("END",END);
+ addKeyBinding("S+HOME",SELECT_HOME);
+ addKeyBinding("S+END",SELECT_END);
+ addKeyBinding("C+HOME",DOCUMENT_HOME);
+ addKeyBinding("C+END",DOCUMENT_END);
+ addKeyBinding("CS+HOME",SELECT_DOC_HOME);
+ addKeyBinding("CS+END",SELECT_DOC_END);
+
+ addKeyBinding("PAGE_UP",PREV_PAGE);
+ addKeyBinding("PAGE_DOWN",NEXT_PAGE);
+ addKeyBinding("S+PAGE_UP",SELECT_PREV_PAGE);
+ addKeyBinding("S+PAGE_DOWN",SELECT_NEXT_PAGE);
+
+ addKeyBinding("LEFT",PREV_CHAR);
+ addKeyBinding("S+LEFT",SELECT_PREV_CHAR);
+ addKeyBinding("C+LEFT",PREV_WORD);
+ addKeyBinding("CS+LEFT",SELECT_PREV_WORD);
+ addKeyBinding("RIGHT",NEXT_CHAR);
+ addKeyBinding("S+RIGHT",SELECT_NEXT_CHAR);
+ addKeyBinding("C+RIGHT",NEXT_WORD);
+ addKeyBinding("CS+RIGHT",SELECT_NEXT_WORD);
+ addKeyBinding("UP",PREV_LINE);
+ addKeyBinding("S+UP",SELECT_PREV_LINE);
+ addKeyBinding("DOWN",NEXT_LINE);
+ addKeyBinding("S+DOWN",SELECT_NEXT_LINE);
+
+ addKeyBinding("C+ENTER",REPEAT);
+ }
+
+ /**
+ * Adds a key binding to this input handler. The key binding is
+ * a list of white space separated key strokes of the form
+ * [modifiers+]key where modifier is C for Control, A for Alt,
+ * or S for Shift, and key is either a character (a-z) or a field
+ * name in the KeyEvent class prefixed with VK_ (e.g., BACK_SPACE)
+ * @param keyBinding The key binding
+ * @param action The action
+ */
+ public void addKeyBinding(String keyBinding, ActionListener action)
+ {
+ Hashtable current = bindings;
+
+ StringTokenizer st = new StringTokenizer(keyBinding);
+ while(st.hasMoreTokens())
+ {
+ KeyStroke keyStroke = parseKeyStroke(st.nextToken());
+ if(keyStroke == null)
+ return;
+
+ if(st.hasMoreTokens())
+ {
+ Object o = current.get(keyStroke);
+ if(o instanceof Hashtable)
+ current = (Hashtable)o;
+ else
+ {
+ o = new Hashtable();
+ current.put(keyStroke,o);
+ current = (Hashtable)o;
+ }
+ }
+ else
+ current.put(keyStroke,action);
+ }
+ }
+
+ /**
+ * Removes a key binding from this input handler. This is not yet
+ * implemented.
+ * @param keyBinding The key binding
+ */
+ public void removeKeyBinding(String keyBinding)
+ {
+ throw new InternalError("Not yet implemented");
+ }
+
+ /**
+ * Removes all key bindings from this input handler.
+ */
+ public void removeAllKeyBindings()
+ {
+ bindings.clear();
+ }
+
+ /**
+ * Returns a copy of this input handler that shares the same
+ * key bindings. Setting key bindings in the copy will also
+ * set them in the original.
+ */
+ public InputHandler copy()
+ {
+ return new DefaultInputHandler(this);
+ }
+
+ /**
+ * Handle a key pressed event. This will look up the binding for
+ * the key stroke and execute it.
+ */
+ public void keyPressed(KeyEvent evt)
+ {
+ int keyCode = evt.getKeyCode();
+ int modifiers = evt.getModifiers();
+
+ // moved this earlier so it doesn't get random meta clicks
+ if (keyCode == KeyEvent.VK_CONTROL ||
+ keyCode == KeyEvent.VK_SHIFT ||
+ keyCode == KeyEvent.VK_ALT ||
+ keyCode == KeyEvent.VK_META) {
+ return;
+ }
+
+ // don't get command-s or other menu key equivs on mac
+ // unless it's something that's specifically bound (cmd-left or right)
+ //if ((modifiers & KeyEvent.META_MASK) != 0) return;
+ if ((modifiers & KeyEvent.META_MASK) != 0) {
+ KeyStroke keyStroke = KeyStroke.getKeyStroke(keyCode, modifiers);
+ if (currentBindings.get(keyStroke) == null) {
+ return;
+ }
+ }
+
+ /*
+ char keyChar = evt.getKeyChar();
+ System.out.println("code=" + keyCode + " char=" + keyChar +
+ " charint=" + ((int)keyChar));
+ System.out.println("other codes " + KeyEvent.VK_ALT + " " +
+ KeyEvent.VK_META);
+ */
+
+ if((modifiers & ~KeyEvent.SHIFT_MASK) != 0
+ || evt.isActionKey()
+ || keyCode == KeyEvent.VK_BACK_SPACE
+ || keyCode == KeyEvent.VK_DELETE
+ || keyCode == KeyEvent.VK_ENTER
+ || keyCode == KeyEvent.VK_TAB
+ || keyCode == KeyEvent.VK_ESCAPE)
+ {
+ if(grabAction != null)
+ {
+ handleGrabAction(evt);
+ return;
+ }
+
+ KeyStroke keyStroke = KeyStroke.getKeyStroke(keyCode,
+ modifiers);
+ Object o = currentBindings.get(keyStroke);
+ if(o == null)
+ {
+ // Don't beep if the user presses some
+ // key we don't know about unless a
+ // prefix is active. Otherwise it will
+ // beep when caps lock is pressed, etc.
+ if(currentBindings != bindings)
+ {
+ Toolkit.getDefaultToolkit().beep();
+ // F10 should be passed on, but C+e F10
+ // shouldn't
+ repeatCount = 0;
+ repeat = false;
+ evt.consume();
+ }
+ currentBindings = bindings;
+ return;
+ }
+ else if(o instanceof ActionListener)
+ {
+ currentBindings = bindings;
+
+ executeAction(((ActionListener)o),
+ evt.getSource(),null);
+
+ evt.consume();
+ return;
+ }
+ else if(o instanceof Hashtable)
+ {
+ currentBindings = (Hashtable)o;
+ evt.consume();
+ return;
+ }
+ }
+ }
+
+ /**
+ * Handle a key typed event. This inserts the key into the text area.
+ */
+ public void keyTyped(KeyEvent evt)
+ {
+ int modifiers = evt.getModifiers();
+ char c = evt.getKeyChar();
+
+ // this is the apple/cmd key on macosx.. so menu commands
+ // were being passed through as legit keys.. added this line
+ // in an attempt to prevent.
+ if ((modifiers & KeyEvent.META_MASK) != 0) return;
+
+ if (c != KeyEvent.CHAR_UNDEFINED) // &&
+ // (modifiers & KeyEvent.ALT_MASK) == 0)
+ {
+ if(c >= 0x20 && c != 0x7f)
+ {
+ KeyStroke keyStroke = KeyStroke.getKeyStroke(
+ Character.toUpperCase(c));
+ Object o = currentBindings.get(keyStroke);
+
+ if(o instanceof Hashtable)
+ {
+ currentBindings = (Hashtable)o;
+ return;
+ }
+ else if(o instanceof ActionListener)
+ {
+ currentBindings = bindings;
+ executeAction((ActionListener)o,
+ evt.getSource(),
+ String.valueOf(c));
+ return;
+ }
+
+ currentBindings = bindings;
+
+ if(grabAction != null)
+ {
+ handleGrabAction(evt);
+ return;
+ }
+
+ // 0-9 adds another 'digit' to the repeat number
+ if(repeat && Character.isDigit(c))
+ {
+ repeatCount *= 10;
+ repeatCount += (c - '0');
+ return;
+ }
+
+ executeAction(INSERT_CHAR,evt.getSource(),
+ String.valueOf(evt.getKeyChar()));
+
+ repeatCount = 0;
+ repeat = false;
+ }
+ }
+ }
+
+ /**
+ * Converts a string to a keystroke. The string should be of the
+ * form modifiers+shortcut where modifiers
+ * is any combination of A for Alt, C for Control, S for Shift
+ * or M for Meta, and shortcut is either a single character,
+ * or a keycode name from the KeyEvent class, without
+ * the VK_ prefix.
+ * @param keyStroke A string description of the key stroke
+ */
+ public static KeyStroke parseKeyStroke(String keyStroke)
+ {
+ if(keyStroke == null)
+ return null;
+ int modifiers = 0;
+ int index = keyStroke.indexOf('+');
+ if(index != -1)
+ {
+ for(int i = 0; i < index; i++)
+ {
+ switch(Character.toUpperCase(keyStroke
+ .charAt(i)))
+ {
+ case 'A':
+ modifiers |= InputEvent.ALT_MASK;
+ break;
+ case 'C':
+ modifiers |= InputEvent.CTRL_MASK;
+ break;
+ case 'M':
+ modifiers |= InputEvent.META_MASK;
+ break;
+ case 'S':
+ modifiers |= InputEvent.SHIFT_MASK;
+ break;
+ }
+ }
+ }
+ String key = keyStroke.substring(index + 1);
+ if(key.length() == 1)
+ {
+ char ch = Character.toUpperCase(key.charAt(0));
+ if(modifiers == 0)
+ return KeyStroke.getKeyStroke(ch);
+ else
+ return KeyStroke.getKeyStroke(ch,modifiers);
+ }
+ else if(key.length() == 0)
+ {
+ System.err.println("Invalid key stroke: " + keyStroke);
+ return null;
+ }
+ else
+ {
+ int ch;
+
+ try
+ {
+ ch = KeyEvent.class.getField("VK_".concat(key))
+ .getInt(null);
+ }
+ catch(Exception e)
+ {
+ System.err.println("Invalid key stroke: "
+ + keyStroke);
+ return null;
+ }
+
+ return KeyStroke.getKeyStroke(ch,modifiers);
+ }
+ }
+
+ // private members
+ private Hashtable bindings;
+ private Hashtable currentBindings;
+
+ private DefaultInputHandler(DefaultInputHandler copy)
+ {
+ bindings = currentBindings = copy.bindings;
+ }
+}
diff --git a/app/src/processing/app/syntax/InputHandler.java b/app/src/processing/app/syntax/InputHandler.java
new file mode 100644
index 000000000..db7260da5
--- /dev/null
+++ b/app/src/processing/app/syntax/InputHandler.java
@@ -0,0 +1,1102 @@
+/*
+ * InputHandler.java - Manages key bindings and executes actions
+ * Copyright (C) 1999 Slava Pestov
+ *
+ * You may use and modify this package for any purpose. Redistribution is
+ * permitted, in both source and binary form, provided that this notice
+ * remains intact in all source distributions of this package.
+ */
+
+package processing.app.syntax;
+
+import javax.swing.text.*;
+import javax.swing.JPopupMenu;
+import java.awt.event.*;
+import java.awt.Component;
+import java.util.*;
+
+/**
+ * An input handler converts the user's key strokes into concrete actions.
+ * It also takes care of macro recording and action repetition.
+ *
+ * This class provides all the necessary support code for an input
+ * handler, but doesn't actually do any key binding logic. It is up
+ * to the implementations of this class to do so.
+ *
+ * @author Slava Pestov
+ * @version $Id: InputHandler.java 4168 2008-08-09 17:24:37Z fry $
+ */
+public abstract class InputHandler extends KeyAdapter
+{
+ /**
+ * If this client property is set to Boolean.TRUE on the text area,
+ * the home/end keys will support 'smart' BRIEF-like behaviour
+ * (one press = start/end of line, two presses = start/end of
+ * viewscreen, three presses = start/end of document). By default,
+ * this property is not set.
+ */
+ public static final String SMART_HOME_END_PROPERTY = "InputHandler.homeEnd";
+
+ public static final ActionListener BACKSPACE = new backspace();
+ public static final ActionListener BACKSPACE_WORD = new backspace_word();
+ public static final ActionListener DELETE = new delete();
+ public static final ActionListener DELETE_WORD = new delete_word();
+ public static final ActionListener END = new end(false);
+ public static final ActionListener DOCUMENT_END = new document_end(false);
+ public static final ActionListener SELECT_END = new end(true);
+ public static final ActionListener SELECT_DOC_END = new document_end(true);
+ public static final ActionListener INSERT_BREAK = new insert_break();
+ public static final ActionListener INSERT_TAB = new insert_tab();
+ public static final ActionListener HOME = new home(false);
+ public static final ActionListener DOCUMENT_HOME = new document_home(false);
+ public static final ActionListener SELECT_HOME = new home(true);
+ public static final ActionListener SELECT_DOC_HOME = new document_home(true);
+ public static final ActionListener NEXT_CHAR = new next_char(false);
+ public static final ActionListener NEXT_LINE = new next_line(false);
+ public static final ActionListener NEXT_PAGE = new next_page(false);
+ public static final ActionListener NEXT_WORD = new next_word(false);
+ public static final ActionListener SELECT_NEXT_CHAR = new next_char(true);
+ public static final ActionListener SELECT_NEXT_LINE = new next_line(true);
+ public static final ActionListener SELECT_NEXT_PAGE = new next_page(true);
+ public static final ActionListener SELECT_NEXT_WORD = new next_word(true);
+ public static final ActionListener OVERWRITE = new overwrite();
+ public static final ActionListener PREV_CHAR = new prev_char(false);
+ public static final ActionListener PREV_LINE = new prev_line(false);
+ public static final ActionListener PREV_PAGE = new prev_page(false);
+ public static final ActionListener PREV_WORD = new prev_word(false);
+ public static final ActionListener SELECT_PREV_CHAR = new prev_char(true);
+ public static final ActionListener SELECT_PREV_LINE = new prev_line(true);
+ public static final ActionListener SELECT_PREV_PAGE = new prev_page(true);
+ public static final ActionListener SELECT_PREV_WORD = new prev_word(true);
+ public static final ActionListener REPEAT = new repeat();
+ public static final ActionListener TOGGLE_RECT = new toggle_rect();
+
+ // Default action
+ public static final ActionListener INSERT_CHAR = new insert_char();
+
+ private static Hashtable actions;
+
+ static
+ {
+ actions = new Hashtable();
+ actions.put("backspace",BACKSPACE);
+ actions.put("backspace-word",BACKSPACE_WORD);
+ actions.put("delete",DELETE);
+ actions.put("delete-word",DELETE_WORD);
+ actions.put("end",END);
+ actions.put("select-end",SELECT_END);
+ actions.put("document-end",DOCUMENT_END);
+ actions.put("select-doc-end",SELECT_DOC_END);
+ actions.put("insert-break",INSERT_BREAK);
+ actions.put("insert-tab",INSERT_TAB);
+ actions.put("home",HOME);
+ actions.put("select-home",SELECT_HOME);
+ actions.put("document-home",DOCUMENT_HOME);
+ actions.put("select-doc-home",SELECT_DOC_HOME);
+ actions.put("next-char",NEXT_CHAR);
+ actions.put("next-line",NEXT_LINE);
+ actions.put("next-page",NEXT_PAGE);
+ actions.put("next-word",NEXT_WORD);
+ actions.put("select-next-char",SELECT_NEXT_CHAR);
+ actions.put("select-next-line",SELECT_NEXT_LINE);
+ actions.put("select-next-page",SELECT_NEXT_PAGE);
+ actions.put("select-next-word",SELECT_NEXT_WORD);
+ actions.put("overwrite",OVERWRITE);
+ actions.put("prev-char",PREV_CHAR);
+ actions.put("prev-line",PREV_LINE);
+ actions.put("prev-page",PREV_PAGE);
+ actions.put("prev-word",PREV_WORD);
+ actions.put("select-prev-char",SELECT_PREV_CHAR);
+ actions.put("select-prev-line",SELECT_PREV_LINE);
+ actions.put("select-prev-page",SELECT_PREV_PAGE);
+ actions.put("select-prev-word",SELECT_PREV_WORD);
+ actions.put("repeat",REPEAT);
+ actions.put("toggle-rect",TOGGLE_RECT);
+ actions.put("insert-char",INSERT_CHAR);
+ }
+
+ /**
+ * Returns a named text area action.
+ * @param name The action name
+ */
+ public static ActionListener getAction(String name)
+ {
+ return (ActionListener)actions.get(name);
+ }
+
+ /**
+ * Returns the name of the specified text area action.
+ * @param listener The action
+ */
+ public static String getActionName(ActionListener listener)
+ {
+ Enumeration en = getActions();
+ while(en.hasMoreElements())
+ {
+ String name = (String)en.nextElement();
+ ActionListener _listener = getAction(name);
+ if(_listener == listener) {
+ return name;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns an enumeration of all available actions.
+ */
+ public static Enumeration getActions()
+ {
+ return actions.keys();
+ }
+
+ /**
+ * Adds the default key bindings to this input handler.
+ * This should not be called in the constructor of this
+ * input handler, because applications might load the
+ * key bindings from a file, etc.
+ */
+ public abstract void addDefaultKeyBindings();
+
+ /**
+ * Adds a key binding to this input handler.
+ * @param keyBinding The key binding (the format of this is
+ * input-handler specific)
+ * @param action The action
+ */
+ public abstract void addKeyBinding(String keyBinding, ActionListener action);
+
+ /**
+ * Removes a key binding from this input handler.
+ * @param keyBinding The key binding
+ */
+ public abstract void removeKeyBinding(String keyBinding);
+
+ /**
+ * Removes all key bindings from this input handler.
+ */
+ public abstract void removeAllKeyBindings();
+
+ /**
+ * Grabs the next key typed event and invokes the specified
+ * action with the key as a the action command.
+ */
+ public void grabNextKeyStroke(ActionListener listener)
+ {
+ grabAction = listener;
+ }
+
+ /**
+ * Returns if repeating is enabled. When repeating is enabled,
+ * actions will be executed multiple times. This is usually
+ * invoked with a special key stroke in the input handler.
+ */
+ public boolean isRepeatEnabled()
+ {
+ return repeat;
+ }
+
+ /**
+ * Enables repeating. When repeating is enabled, actions will be
+ * executed multiple times. Once repeating is enabled, the input
+ * handler should read a number from the keyboard.
+ */
+ public void setRepeatEnabled(boolean repeat)
+ {
+ this.repeat = repeat;
+ }
+
+ /**
+ * Returns the number of times the next action will be repeated.
+ */
+ public int getRepeatCount()
+ {
+ return (repeat ? Math.max(1,repeatCount) : 1);
+ }
+
+ /**
+ * Sets the number of times the next action will be repeated.
+ * @param repeatCount The repeat count
+ */
+ public void setRepeatCount(int repeatCount)
+ {
+ this.repeatCount = repeatCount;
+ }
+
+ /**
+ * Returns the macro recorder. If this is non-null, all executed
+ * actions should be forwarded to the recorder.
+ */
+ public InputHandler.MacroRecorder getMacroRecorder()
+ {
+ return recorder;
+ }
+
+ /**
+ * Sets the macro recorder. If this is non-null, all executed
+ * actions should be forwarded to the recorder.
+ * @param recorder The macro recorder
+ */
+ public void setMacroRecorder(InputHandler.MacroRecorder recorder)
+ {
+ this.recorder = recorder;
+ }
+
+ /**
+ * Returns a copy of this input handler that shares the same
+ * key bindings. Setting key bindings in the copy will also
+ * set them in the original.
+ */
+ public abstract InputHandler copy();
+
+ /**
+ * Executes the specified action, repeating and recording it as
+ * necessary.
+ * @param listener The action listener
+ * @param source The event source
+ * @param actionCommand The action command
+ */
+ public void executeAction(ActionListener listener, Object source,
+ String actionCommand)
+ {
+ // create event
+ ActionEvent evt = new ActionEvent(source,
+ ActionEvent.ACTION_PERFORMED,
+ actionCommand);
+
+ // don't do anything if the action is a wrapper
+ // (like EditAction.Wrapper)
+ if(listener instanceof Wrapper)
+ {
+ listener.actionPerformed(evt);
+ return;
+ }
+
+ // remember old values, in case action changes them
+ boolean _repeat = repeat;
+ int _repeatCount = getRepeatCount();
+
+ // execute the action
+ if(listener instanceof InputHandler.NonRepeatable)
+ listener.actionPerformed(evt);
+ else
+ {
+ for(int i = 0; i < Math.max(1,repeatCount); i++)
+ listener.actionPerformed(evt);
+ }
+
+ // do recording. Notice that we do no recording whatsoever
+ // for actions that grab keys
+ if(grabAction == null)
+ {
+ if(recorder != null)
+ {
+ if(!(listener instanceof InputHandler.NonRecordable))
+ {
+ if(_repeatCount != 1)
+ recorder.actionPerformed(REPEAT,String.valueOf(_repeatCount));
+
+ recorder.actionPerformed(listener,actionCommand);
+ }
+ }
+
+ // If repeat was true originally, clear it
+ // Otherwise it might have been set by the action, etc
+ if(_repeat)
+ {
+ repeat = false;
+ repeatCount = 0;
+ }
+ }
+ }
+
+ /**
+ * Returns the text area that fired the specified event.
+ * @param evt The event
+ */
+ public static JEditTextArea getTextArea(EventObject evt)
+ {
+ if(evt != null)
+ {
+ Object o = evt.getSource();
+ if(o instanceof Component)
+ {
+ // find the parent text area
+ Component c = (Component)o;
+ for(;;)
+ {
+ if(c instanceof JEditTextArea)
+ return (JEditTextArea)c;
+ else if(c == null)
+ break;
+ if(c instanceof JPopupMenu)
+ c = ((JPopupMenu)c)
+ .getInvoker();
+ else
+ c = c.getParent();
+ }
+ }
+ }
+
+ // this shouldn't happen
+ System.err.println("BUG: getTextArea() returning null");
+ System.err.println("Report this to Slava Pestov ");
+ return null;
+ }
+
+ // protected members
+
+ /**
+ * If a key is being grabbed, this method should be called with
+ * the appropriate key event. It executes the grab action with
+ * the typed character as the parameter.
+ */
+ protected void handleGrabAction(KeyEvent evt)
+ {
+ // Clear it *before* it is executed so that executeAction()
+ // resets the repeat count
+ ActionListener _grabAction = grabAction;
+ grabAction = null;
+ executeAction(_grabAction,evt.getSource(),
+ String.valueOf(evt.getKeyChar()));
+ }
+
+ // protected members
+ protected ActionListener grabAction;
+ protected boolean repeat;
+ protected int repeatCount;
+ protected InputHandler.MacroRecorder recorder;
+
+ /**
+ * If an action implements this interface, it should not be repeated.
+ * Instead, it will handle the repetition itself.
+ */
+ public interface NonRepeatable {}
+
+ /**
+ * If an action implements this interface, it should not be recorded
+ * by the macro recorder. Instead, it will do its own recording.
+ */
+ public interface NonRecordable {}
+
+ /**
+ * For use by EditAction.Wrapper only.
+ * @since jEdit 2.2final
+ */
+ public interface Wrapper {}
+
+ /**
+ * Macro recorder.
+ */
+ public interface MacroRecorder
+ {
+ void actionPerformed(ActionListener listener,
+ String actionCommand);
+ }
+
+ public static class backspace implements ActionListener
+ {
+ public void actionPerformed(ActionEvent evt)
+ {
+ JEditTextArea textArea = getTextArea(evt);
+
+ if(!textArea.isEditable())
+ {
+ textArea.getToolkit().beep();
+ return;
+ }
+
+ if(textArea.getSelectionStart()
+ != textArea.getSelectionStop())
+ {
+ textArea.setSelectedText("");
+ }
+ else
+ {
+ int caret = textArea.getCaretPosition();
+ if(caret == 0)
+ {
+ textArea.getToolkit().beep();
+ return;
+ }
+ try
+ {
+ textArea.getDocument().remove(caret - 1,1);
+ }
+ catch(BadLocationException bl)
+ {
+ bl.printStackTrace();
+ }
+ }
+ }
+ }
+
+ public static class backspace_word implements ActionListener
+ {
+ public void actionPerformed(ActionEvent evt)
+ {
+ JEditTextArea textArea = getTextArea(evt);
+ int start = textArea.getSelectionStart();
+ if(start != textArea.getSelectionStop())
+ {
+ textArea.setSelectedText("");
+ }
+
+ int line = textArea.getCaretLine();
+ int lineStart = textArea.getLineStartOffset(line);
+ int caret = start - lineStart;
+
+ String lineText = textArea.getLineText(textArea
+ .getCaretLine());
+
+ if(caret == 0)
+ {
+ if(lineStart == 0)
+ {
+ textArea.getToolkit().beep();
+ return;
+ }
+ caret--;
+ }
+ else
+ {
+ String noWordSep = (String)textArea.getDocument().getProperty("noWordSep");
+ caret = TextUtilities.findWordStart(lineText,caret,noWordSep);
+ }
+
+ try
+ {
+ textArea.getDocument().remove(
+ caret + lineStart,
+ start - (caret + lineStart));
+ }
+ catch(BadLocationException bl)
+ {
+ bl.printStackTrace();
+ }
+ }
+ }
+
+ public static class delete implements ActionListener
+ {
+ public void actionPerformed(ActionEvent evt)
+ {
+ JEditTextArea textArea = getTextArea(evt);
+
+ if(!textArea.isEditable())
+ {
+ textArea.getToolkit().beep();
+ return;
+ }
+
+ if(textArea.getSelectionStart()
+ != textArea.getSelectionStop())
+ {
+ textArea.setSelectedText("");
+ }
+ else
+ {
+ int caret = textArea.getCaretPosition();
+ if(caret == textArea.getDocumentLength())
+ {
+ textArea.getToolkit().beep();
+ return;
+ }
+ try
+ {
+ textArea.getDocument().remove(caret,1);
+ }
+ catch(BadLocationException bl)
+ {
+ bl.printStackTrace();
+ }
+ }
+ }
+ }
+
+ public static class delete_word implements ActionListener
+ {
+ public void actionPerformed(ActionEvent evt)
+ {
+ JEditTextArea textArea = getTextArea(evt);
+ int start = textArea.getSelectionStart();
+ if(start != textArea.getSelectionStop())
+ {
+ textArea.setSelectedText("");
+ }
+
+ int line = textArea.getCaretLine();
+ int lineStart = textArea.getLineStartOffset(line);
+ int caret = start - lineStart;
+
+ String lineText = textArea.getLineText(textArea
+ .getCaretLine());
+
+ if(caret == lineText.length())
+ {
+ if(lineStart + caret == textArea.getDocumentLength())
+ {
+ textArea.getToolkit().beep();
+ return;
+ }
+ caret++;
+ }
+ else
+ {
+ String noWordSep = (String)textArea.getDocument().getProperty("noWordSep");
+ caret = TextUtilities.findWordEnd(lineText,caret,noWordSep);
+ }
+
+ try
+ {
+ textArea.getDocument().remove(start,
+ (caret + lineStart) - start);
+ }
+ catch(BadLocationException bl)
+ {
+ bl.printStackTrace();
+ }
+ }
+ }
+
+ public static class end implements ActionListener
+ {
+ private boolean select;
+
+ public end(boolean select)
+ {
+ this.select = select;
+ }
+
+ public void actionPerformed(ActionEvent evt)
+ {
+ JEditTextArea textArea = getTextArea(evt);
+
+ int caret = textArea.getCaretPosition();
+
+ int lastOfLine = textArea.getLineStopOffset(
+ textArea.getCaretLine()) - 1;
+ int lastVisibleLine = textArea.getFirstLine()
+ + textArea.getVisibleLines();
+ if(lastVisibleLine >= textArea.getLineCount())
+ {
+ lastVisibleLine = Math.min(textArea.getLineCount() - 1,
+ lastVisibleLine);
+ }
+ else
+ lastVisibleLine -= (textArea.getElectricScroll() + 1);
+
+ int lastVisible = textArea.getLineStopOffset(lastVisibleLine) - 1;
+ int lastDocument = textArea.getDocumentLength();
+
+ if(caret == lastDocument)
+ {
+ textArea.getToolkit().beep();
+ return;
+ }
+ else if(!Boolean.TRUE.equals(textArea.getClientProperty(
+ SMART_HOME_END_PROPERTY)))
+ caret = lastOfLine;
+ else if(caret == lastVisible)
+ caret = lastDocument;
+ else if(caret == lastOfLine)
+ caret = lastVisible;
+ else
+ caret = lastOfLine;
+
+ if(select)
+ textArea.select(textArea.getMarkPosition(),caret);
+ else
+ textArea.setCaretPosition(caret);
+ }
+ }
+
+ public static class document_end implements ActionListener
+ {
+ private boolean select;
+
+ public document_end(boolean select)
+ {
+ this.select = select;
+ }
+
+ public void actionPerformed(ActionEvent evt)
+ {
+ JEditTextArea textArea = getTextArea(evt);
+ if(select)
+ textArea.select(textArea.getMarkPosition(),
+ textArea.getDocumentLength());
+ else
+ textArea.setCaretPosition(textArea
+ .getDocumentLength());
+ }
+ }
+
+ public static class home implements ActionListener
+ {
+ private boolean select;
+
+ public home(boolean select)
+ {
+ this.select = select;
+ }
+
+ public void actionPerformed(ActionEvent evt)
+ {
+ JEditTextArea textArea = getTextArea(evt);
+
+ int caret = textArea.getCaretPosition();
+
+ int firstLine = textArea.getFirstLine();
+
+ int firstOfLine = textArea.getLineStartOffset(
+ textArea.getCaretLine());
+ int firstVisibleLine = (firstLine == 0 ? 0 :
+ firstLine + textArea.getElectricScroll());
+ int firstVisible = textArea.getLineStartOffset(
+ firstVisibleLine);
+
+ if(caret == 0)
+ {
+ textArea.getToolkit().beep();
+ return;
+ }
+ else if(!Boolean.TRUE.equals(textArea.getClientProperty(
+ SMART_HOME_END_PROPERTY)))
+ caret = firstOfLine;
+ else if(caret == firstVisible)
+ caret = 0;
+ else if(caret == firstOfLine)
+ caret = firstVisible;
+ else
+ caret = firstOfLine;
+
+ if(select)
+ textArea.select(textArea.getMarkPosition(),caret);
+ else
+ textArea.setCaretPosition(caret);
+ }
+ }
+
+ public static class document_home implements ActionListener
+ {
+ private boolean select;
+
+ public document_home(boolean select)
+ {
+ this.select = select;
+ }
+
+ public void actionPerformed(ActionEvent evt)
+ {
+ JEditTextArea textArea = getTextArea(evt);
+ if(select)
+ textArea.select(textArea.getMarkPosition(),0);
+ else
+ textArea.setCaretPosition(0);
+ }
+ }
+
+ public static class insert_break implements ActionListener
+ {
+ public void actionPerformed(ActionEvent evt)
+ {
+ JEditTextArea textArea = getTextArea(evt);
+
+ if(!textArea.isEditable())
+ {
+ textArea.getToolkit().beep();
+ return;
+ }
+
+ textArea.setSelectedText("\n");
+ }
+ }
+
+ public static class insert_tab implements ActionListener
+ {
+ public void actionPerformed(ActionEvent evt)
+ {
+ JEditTextArea textArea = getTextArea(evt);
+
+ if(!textArea.isEditable())
+ {
+ textArea.getToolkit().beep();
+ return;
+ }
+
+ textArea.overwriteSetSelectedText("\t");
+ }
+ }
+
+ public static class next_char implements ActionListener
+ {
+ private boolean select;
+
+ public next_char(boolean select)
+ {
+ this.select = select;
+ }
+
+ public void actionPerformed(ActionEvent evt)
+ {
+ JEditTextArea textArea = getTextArea(evt);
+ int caret = textArea.getCaretPosition();
+
+ if(caret == textArea.getDocumentLength())
+ {
+ if (textArea.getSelectionStart() !=
+ textArea.getSelectionStop()) {
+ // just move to the end of the selection
+ textArea.select(caret, caret);
+ } else {
+ // beep at the user for being annoying
+ textArea.getToolkit().beep();
+ }
+
+ } else if (select) {
+ textArea.select(textArea.getMarkPosition(), caret+1);
+
+ } else {
+ int start = textArea.getSelectionStart();
+ int end = textArea.getSelectionStop();
+ if (start != end) {
+ textArea.select(end, end);
+ } else {
+ textArea.setCaretPosition(caret + 1);
+ }
+ }
+ }
+ }
+
+ public static class next_line implements ActionListener
+ {
+ private boolean select;
+
+ public next_line(boolean select)
+ {
+ this.select = select;
+ }
+
+ public void actionPerformed(ActionEvent evt)
+ {
+ JEditTextArea textArea = getTextArea(evt);
+ int caret = textArea.getCaretPosition();
+ int line = textArea.getCaretLine();
+
+ if(line == textArea.getLineCount() - 1)
+ {
+ //textArea.getToolkit().beep();
+ int doc = textArea.getDocumentLength();
+ if (select) {
+ textArea.select(textArea.getMarkPosition(), doc);
+ } else {
+ textArea.setCaretPosition(doc);
+ }
+ return;
+ }
+
+ int magic = textArea.getMagicCaretPosition();
+ if(magic == -1)
+ {
+ magic = textArea.offsetToX(line,
+ caret - textArea.getLineStartOffset(line));
+ }
+
+ caret = textArea.getLineStartOffset(line + 1)
+ + textArea.xToOffset(line + 1,magic);
+ if(select)
+ textArea.select(textArea.getMarkPosition(),caret);
+ else
+ textArea.setCaretPosition(caret);
+ textArea.setMagicCaretPosition(magic);
+ }
+ }
+
+ public static class next_page implements ActionListener
+ {
+ private boolean select;
+
+ public next_page(boolean select)
+ {
+ this.select = select;
+ }
+
+ public void actionPerformed(ActionEvent evt)
+ {
+ JEditTextArea textArea = getTextArea(evt);
+ int lineCount = textArea.getLineCount();
+ int firstLine = textArea.getFirstLine();
+ int visibleLines = textArea.getVisibleLines();
+ int line = textArea.getCaretLine();
+
+ firstLine += visibleLines;
+
+ if(firstLine + visibleLines >= lineCount - 1)
+ firstLine = lineCount - visibleLines;
+
+ textArea.setFirstLine(firstLine);
+
+ int caret = textArea.getLineStartOffset(
+ Math.min(textArea.getLineCount() - 1,
+ line + visibleLines));
+ if(select)
+ textArea.select(textArea.getMarkPosition(),caret);
+ else
+ textArea.setCaretPosition(caret);
+ }
+ }
+
+ public static class next_word implements ActionListener
+ {
+ private boolean select;
+
+ public next_word(boolean select)
+ {
+ this.select = select;
+ }
+
+ public void actionPerformed(ActionEvent evt)
+ {
+ JEditTextArea textArea = getTextArea(evt);
+ int caret = textArea.getCaretPosition();
+ int line = textArea.getCaretLine();
+ int lineStart = textArea.getLineStartOffset(line);
+ caret -= lineStart;
+
+ String lineText = textArea.getLineText(textArea
+ .getCaretLine());
+
+ if(caret == lineText.length())
+ {
+ if(lineStart + caret == textArea.getDocumentLength())
+ {
+ textArea.getToolkit().beep();
+ return;
+ }
+ caret++;
+ }
+ else
+ {
+ String noWordSep = (String)textArea.getDocument().getProperty("noWordSep");
+ caret = TextUtilities.findWordEnd(lineText,caret,noWordSep);
+ }
+
+ if(select)
+ textArea.select(textArea.getMarkPosition(),
+ lineStart + caret);
+ else
+ textArea.setCaretPosition(lineStart + caret);
+ }
+ }
+
+ public static class overwrite implements ActionListener
+ {
+ public void actionPerformed(ActionEvent evt)
+ {
+ JEditTextArea textArea = getTextArea(evt);
+ textArea.setOverwriteEnabled(
+ !textArea.isOverwriteEnabled());
+ }
+ }
+
+ public static class prev_char implements ActionListener
+ {
+ private boolean select;
+
+ public prev_char(boolean select)
+ {
+ this.select = select;
+ }
+
+ public void actionPerformed(ActionEvent evt)
+ {
+ JEditTextArea textArea = getTextArea(evt);
+ int caret = textArea.getCaretPosition();
+ if(caret == 0)
+ {
+ textArea.getToolkit().beep();
+ return;
+ }
+
+ if (select) {
+ textArea.select(textArea.getMarkPosition(), caret-1);
+ } else {
+ int start = textArea.getSelectionStart();
+ int end = textArea.getSelectionStop();
+ if (start != end) {
+ textArea.select(start, start);
+ } else {
+ textArea.setCaretPosition(caret - 1);
+ }
+ }
+ }
+ }
+
+ public static class prev_line implements ActionListener
+ {
+ private boolean select;
+
+ public prev_line(boolean select)
+ {
+ this.select = select;
+ }
+
+ public void actionPerformed(ActionEvent evt)
+ {
+ JEditTextArea textArea = getTextArea(evt);
+ int caret = textArea.getCaretPosition();
+ int line = textArea.getCaretLine();
+
+ if(line == 0)
+ {
+ if (select) {
+ if (textArea.getSelectionStart() != 0) {
+ textArea.select(textArea.getMarkPosition(), 0);
+ }
+ } else {
+ textArea.setCaretPosition(0);
+ }
+ //textArea.getToolkit().beep();
+ return;
+ }
+
+ int magic = textArea.getMagicCaretPosition();
+ if(magic == -1)
+ {
+ magic = textArea.offsetToX(line,
+ caret - textArea.getLineStartOffset(line));
+ }
+
+ caret = textArea.getLineStartOffset(line - 1)
+ + textArea.xToOffset(line - 1,magic);
+ if(select)
+ textArea.select(textArea.getMarkPosition(),caret);
+ else
+ textArea.setCaretPosition(caret);
+ textArea.setMagicCaretPosition(magic);
+ }
+ }
+
+ public static class prev_page implements ActionListener
+ {
+ private boolean select;
+
+ public prev_page(boolean select)
+ {
+ this.select = select;
+ }
+
+ public void actionPerformed(ActionEvent evt)
+ {
+ JEditTextArea textArea = getTextArea(evt);
+ int firstLine = textArea.getFirstLine();
+ int visibleLines = textArea.getVisibleLines();
+ int line = textArea.getCaretLine();
+
+ if(firstLine < visibleLines)
+ firstLine = visibleLines;
+
+ textArea.setFirstLine(firstLine - visibleLines);
+
+ int caret = textArea.getLineStartOffset(
+ Math.max(0,line - visibleLines));
+ if(select)
+ textArea.select(textArea.getMarkPosition(),caret);
+ else
+ textArea.setCaretPosition(caret);
+ }
+ }
+
+ public static class prev_word implements ActionListener
+ {
+ private boolean select;
+
+ public prev_word(boolean select)
+ {
+ this.select = select;
+ }
+
+ public void actionPerformed(ActionEvent evt)
+ {
+ JEditTextArea textArea = getTextArea(evt);
+ int caret = textArea.getCaretPosition();
+ int line = textArea.getCaretLine();
+ int lineStart = textArea.getLineStartOffset(line);
+ caret -= lineStart;
+
+ String lineText = textArea.getLineText(textArea
+ .getCaretLine());
+
+ if(caret == 0)
+ {
+ if(lineStart == 0)
+ {
+ textArea.getToolkit().beep();
+ return;
+ }
+ caret--;
+ }
+ else
+ {
+ String noWordSep = (String)textArea.getDocument().getProperty("noWordSep");
+ caret = TextUtilities.findWordStart(lineText,caret,noWordSep);
+ }
+
+ if(select)
+ textArea.select(textArea.getMarkPosition(),
+ lineStart + caret);
+ else
+ textArea.setCaretPosition(lineStart + caret);
+ }
+ }
+
+ public static class repeat implements ActionListener,
+ InputHandler.NonRecordable
+ {
+ public void actionPerformed(ActionEvent evt)
+ {
+ JEditTextArea textArea = getTextArea(evt);
+ textArea.getInputHandler().setRepeatEnabled(true);
+ String actionCommand = evt.getActionCommand();
+ if(actionCommand != null)
+ {
+ textArea.getInputHandler().setRepeatCount(
+ Integer.parseInt(actionCommand));
+ }
+ }
+ }
+
+ public static class toggle_rect implements ActionListener
+ {
+ public void actionPerformed(ActionEvent evt)
+ {
+ JEditTextArea textArea = getTextArea(evt);
+ textArea.setSelectionRectangular(
+ !textArea.isSelectionRectangular());
+ }
+ }
+
+ public static class insert_char implements ActionListener,
+ InputHandler.NonRepeatable
+ {
+ public void actionPerformed(ActionEvent evt)
+ {
+ JEditTextArea textArea = getTextArea(evt);
+ String str = evt.getActionCommand();
+ int repeatCount = textArea.getInputHandler().getRepeatCount();
+
+ if(textArea.isEditable())
+ {
+ StringBuffer buf = new StringBuffer();
+ for(int i = 0; i < repeatCount; i++)
+ buf.append(str);
+ textArea.overwriteSetSelectedText(buf.toString());
+ }
+ else
+ {
+ textArea.getToolkit().beep();
+ }
+ }
+ }
+}
diff --git a/app/src/processing/app/syntax/JEditTextArea.java b/app/src/processing/app/syntax/JEditTextArea.java
new file mode 100644
index 000000000..af01ea16c
--- /dev/null
+++ b/app/src/processing/app/syntax/JEditTextArea.java
@@ -0,0 +1,2259 @@
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+/*
+ * JEditTextArea.java - jEdit's text component
+ * Copyright (C) 1999 Slava Pestov
+ *
+ * You may use and modify this package for any purpose. Redistribution is
+ * permitted, in both source and binary form, provided that this notice
+ * remains intact in all source distributions of this package.
+ */
+
+package processing.app.syntax;
+
+import processing.app.*;
+
+import javax.swing.event.*;
+import javax.swing.text.*;
+import javax.swing.undo.*;
+import javax.swing.*;
+import java.awt.datatransfer.*;
+import java.awt.event.*;
+import java.awt.*;
+import java.util.Enumeration;
+import java.util.Vector;
+
+/**
+ * jEdit's text area component. It is more suited for editing program
+ * source code than JEditorPane, because it drops the unnecessary features
+ * (images, variable-width lines, and so on) and adds a whole bunch of
+ * useful goodies such as:
+ *
+ *
More flexible key binding scheme
+ *
Supports macro recorders
+ *
Rectangular selection
+ *
Bracket highlighting
+ *
Syntax highlighting
+ *
Command repetition
+ *
Block caret can be enabled
+ *
+ * It is also faster and doesn't have as many problems. It can be used
+ * in other applications; the only other part of jEdit it depends on is
+ * the syntax package.
+ *
+ * To use it in your app, treat it like any other component, for example:
+ *
JEditTextArea ta = new JEditTextArea();
+ * ta.setTokenMarker(new JavaTokenMarker());
+ * ta.setText("public class Test {\n"
+ * + " public static void main(String[] args) {\n"
+ * + " System.out.println(\"Hello World\");\n"
+ * + " }\n"
+ * + "}");
+ *
+ * @author Slava Pestov
+ * @version $Id: JEditTextArea.java 5343 2008-11-29 17:22:59Z fry $
+ */
+public class JEditTextArea extends JComponent
+{
+ /**
+ * Adding components with this name to the text area will place
+ * them left of the horizontal scroll bar. In jEdit, the status
+ * bar is added this way.
+ */
+ public static String LEFT_OF_SCROLLBAR = "los";
+
+ /**
+ * Creates a new JEditTextArea with the default settings.
+ */
+ /*
+ public JEditTextArea()
+ {
+ this(TextAreaDefaults.getDefaults());
+ }
+ */
+
+ /**
+ * Creates a new JEditTextArea with the specified settings.
+ * @param defaults The default settings
+ */
+ public JEditTextArea(TextAreaDefaults defaults)
+ {
+ // Enable the necessary events
+ enableEvents(AWTEvent.KEY_EVENT_MASK);
+
+ // Initialize some misc. stuff
+ painter = new TextAreaPainter(this,defaults);
+ documentHandler = new DocumentHandler();
+ eventListenerList = new EventListenerList();
+ caretEvent = new MutableCaretEvent();
+ lineSegment = new Segment();
+ bracketLine = bracketPosition = -1;
+ blink = true;
+
+ // Initialize the GUI
+ setLayout(new ScrollLayout());
+ add(CENTER, painter);
+ add(RIGHT, vertical = new JScrollBar(JScrollBar.VERTICAL));
+ add(BOTTOM, horizontal = new JScrollBar(JScrollBar.HORIZONTAL));
+
+ // Add some event listeners
+ vertical.addAdjustmentListener(new AdjustHandler());
+ horizontal.addAdjustmentListener(new AdjustHandler());
+ painter.addComponentListener(new ComponentHandler());
+ painter.addMouseListener(new MouseHandler());
+ painter.addMouseMotionListener(new DragHandler());
+ addFocusListener(new FocusHandler());
+
+ // Load the defaults
+ setInputHandler(defaults.inputHandler);
+ setDocument(defaults.document);
+ editable = defaults.editable;
+ caretVisible = defaults.caretVisible;
+ caretBlinks = defaults.caretBlinks;
+ electricScroll = defaults.electricScroll;
+
+ // We don't seem to get the initial focus event?
+ focusedComponent = this;
+
+ addMouseWheelListener(new MouseWheelListener() {
+ public void mouseWheelMoved(MouseWheelEvent e) {
+ if (!scrollBarsInitialized) return;
+ int amt = e.getWheelRotation();
+ vertical.setValue(vertical.getValue() + amt * 3);
+ }
+ });
+ }
+
+
+ /**
+ * Get current position of the vertical scroll bar. [fry]
+ */
+ public int getScrollPosition() {
+ return vertical.getValue();
+ }
+
+
+ /**
+ * Set position of the vertical scroll bar. [fry]
+ */
+ public void setScrollPosition(int what) {
+ vertical.setValue(what);
+ }
+
+
+ /**
+ * Returns if this component can be traversed by pressing
+ * the Tab key. This returns false.
+ */
+ public final boolean isManagingFocus() {
+ return true;
+ }
+
+ /**
+ * Returns the object responsible for painting this text area.
+ */
+ public final TextAreaPainter getPainter() {
+ return painter;
+ }
+
+ /**
+ * Returns the input handler.
+ */
+ public final InputHandler getInputHandler() {
+ return inputHandler;
+ }
+
+ /**
+ * Sets the input handler.
+ * @param inputHandler The new input handler
+ */
+ public void setInputHandler(InputHandler inputHandler) {
+ this.inputHandler = inputHandler;
+ }
+
+ /**
+ * Returns true if the caret is blinking, false otherwise.
+ */
+ public final boolean isCaretBlinkEnabled() {
+ return caretBlinks;
+ }
+
+ /**
+ * Toggles caret blinking.
+ * @param caretBlinks True if the caret should blink, false otherwise
+ */
+ public void setCaretBlinkEnabled(boolean caretBlinks) {
+ this.caretBlinks = caretBlinks;
+ if(!caretBlinks)
+ blink = false;
+
+ painter.invalidateSelectedLines();
+ }
+
+ /**
+ * Returns true if the caret is visible, false otherwise.
+ */
+ public final boolean isCaretVisible() {
+ return (!caretBlinks || blink) && caretVisible;
+ }
+
+ /**
+ * Sets if the caret should be visible.
+ * @param caretVisible True if the caret should be visible, false
+ * otherwise
+ */
+ public void setCaretVisible(boolean caretVisible) {
+ this.caretVisible = caretVisible;
+ blink = true;
+
+ painter.invalidateSelectedLines();
+ }
+
+ /**
+ * Blinks the caret.
+ */
+ public final void blinkCaret() {
+ if (caretBlinks) {
+ blink = !blink;
+ painter.invalidateSelectedLines();
+ } else {
+ blink = true;
+ }
+ }
+
+ /**
+ * Returns the number of lines from the top and button of the
+ * text area that are always visible.
+ */
+ public final int getElectricScroll() {
+ return electricScroll;
+ }
+
+ /**
+ * Sets the number of lines from the top and bottom of the text
+ * area that are always visible
+ * @param electricScroll The number of lines always visible from
+ * the top or bottom
+ */
+ public final void setElectricScroll(int electricScroll) {
+ this.electricScroll = electricScroll;
+ }
+
+
+ /**
+ * Updates the state of the scroll bars. This should be called
+ * if the number of lines in the document changes, or when the
+ * size of the text are changes.
+ */
+ public void updateScrollBars() {
+ if (vertical != null && visibleLines != 0) {
+ vertical.setValues(firstLine,visibleLines,0,getLineCount());
+ vertical.setUnitIncrement(2);
+ vertical.setBlockIncrement(visibleLines);
+ }
+
+ //if (horizontal != null && width != 0) {
+ if ((horizontal != null) && (painter.getWidth() != 0)) {
+ //int value = horizontal.getValue();
+ //System.out.println("updateScrollBars");
+ //int width = painter.getWidth();
+ int lineCount = getLineCount();
+ int maxLineLength = 0;
+ for (int i = 0; i < lineCount; i++) {
+ int lineLength = getLineLength(i);
+ if (lineLength > maxLineLength) {
+ maxLineLength = lineLength;
+ }
+ }
+ int charWidth = painter.getFontMetrics().charWidth('w');
+ int width = maxLineLength * charWidth;
+ int painterWidth = painter.getWidth();
+ //System.out.println("max line len " + maxLineLength);
+ //System.out.println("width " + width);
+ //System.out.println("text area width " + painter.getWidth());
+
+ // this was the default, but it's enormous
+ //horizontal.setValues(-horizontalOffset,width,0,width * 5);
+
+ // something more reasonable, though this is a bad solution
+ //horizontal.setValues(-horizontalOffset,width,0,width * 2);
+
+ // in general.. time to start looking at that other syntax pkg
+ // since most code should fit the window horizontally, just use
+ // the default settings for the width, this is a nicer solution
+ // until a better update mechanism can be implemented [fry]
+
+ //horizontal.setValues(0, width, 0, width);
+ //0, width - horizontalOffset);
+ // works, from pre-75 versions of p5
+ //horizontal.setValues(-horizontalOffset, width, 0, width);
+
+ // gets weird when writing to the end of lines
+ //horizontal.setValues(value, painterWidth, 0, width);
+
+ // seems to work, implemented for 0075
+ horizontal.setValues(-horizontalOffset, painterWidth, 0, width);
+
+ //horizontal.setUnitIncrement(painter.getFontMetrics().charWidth('w'));
+ horizontal.setUnitIncrement(charWidth);
+ horizontal.setBlockIncrement(width / 2);
+ }
+ }
+
+ /**
+ * Returns the line displayed at the text area's origin.
+ */
+ public final int getFirstLine() {
+ return firstLine;
+ }
+
+ /**
+ * Sets the line displayed at the text area's origin without
+ * updating the scroll bars.
+ */
+ public void setFirstLine(int firstLine) {
+ if (firstLine == this.firstLine) return;
+
+ this.firstLine = firstLine;
+ if (firstLine != vertical.getValue()) {
+ updateScrollBars();
+ }
+ painter.repaint();
+ }
+
+ /**
+ * Returns the number of lines visible in this text area.
+ */
+ public final int getVisibleLines() {
+ return visibleLines;
+ }
+
+ /**
+ * Recalculates the number of visible lines. This should not
+ * be called directly.
+ */
+ public final void recalculateVisibleLines() {
+ if (painter == null) return;
+
+ int height = painter.getHeight();
+ int lineHeight = painter.getFontMetrics().getHeight();
+ visibleLines = height / lineHeight;
+ updateScrollBars();
+ }
+
+ /**
+ * Returns the horizontal offset of drawn lines.
+ */
+ public final int getHorizontalOffset() {
+ return horizontalOffset;
+ }
+
+ /**
+ * Sets the horizontal offset of drawn lines. This can be used to
+ * implement horizontal scrolling.
+ * @param horizontalOffset offset The new horizontal offset
+ */
+ public void setHorizontalOffset(int horizontalOffset)
+ {
+ if(horizontalOffset == this.horizontalOffset)
+ return;
+ this.horizontalOffset = horizontalOffset;
+ if(horizontalOffset != horizontal.getValue())
+ updateScrollBars();
+ painter.repaint();
+ }
+
+ /**
+ * A fast way of changing both the first line and horizontal
+ * offset.
+ * @param firstLine The new first line
+ * @param horizontalOffset The new horizontal offset
+ * @return True if any of the values were changed, false otherwise
+ */
+ public boolean setOrigin(int firstLine, int horizontalOffset)
+ {
+ boolean changed = false;
+ //int oldFirstLine = this.firstLine;
+
+ if(horizontalOffset != this.horizontalOffset)
+ {
+ this.horizontalOffset = horizontalOffset;
+ changed = true;
+ }
+
+ if(firstLine != this.firstLine)
+ {
+ this.firstLine = firstLine;
+ changed = true;
+ }
+
+ if(changed)
+ {
+ updateScrollBars();
+ painter.repaint();
+ }
+
+ return changed;
+ }
+
+ /**
+ * Ensures that the caret is visible by scrolling the text area if
+ * necessary.
+ * @return True if scrolling was actually performed, false if the
+ * caret was already visible
+ */
+ public boolean scrollToCaret()
+ {
+ int line = getCaretLine();
+ int lineStart = getLineStartOffset(line);
+ int offset = Math.max(0,Math.min(getLineLength(line) - 1,
+ getCaretPosition() - lineStart));
+
+ return scrollTo(line,offset);
+ }
+
+ /**
+ * Ensures that the specified line and offset is visible by scrolling
+ * the text area if necessary.
+ * @param line The line to scroll to
+ * @param offset The offset in the line to scroll to
+ * @return True if scrolling was actually performed, false if the
+ * line and offset was already visible
+ */
+ public boolean scrollTo(int line, int offset)
+ {
+ // visibleLines == 0 before the component is realized
+ // we can't do any proper scrolling then, so we have
+ // this hack...
+ if (visibleLines == 0) {
+ setFirstLine(Math.max(0,line - electricScroll));
+ return true;
+ }
+
+ int newFirstLine = firstLine;
+ int newHorizontalOffset = horizontalOffset;
+
+ if(line < firstLine + electricScroll) {
+ newFirstLine = Math.max(0,line - electricScroll);
+
+ } else if(line + electricScroll >= firstLine + visibleLines) {
+ newFirstLine = (line - visibleLines) + electricScroll + 1;
+ if(newFirstLine + visibleLines >= getLineCount())
+ newFirstLine = getLineCount() - visibleLines;
+ if(newFirstLine < 0)
+ newFirstLine = 0;
+ }
+
+ int x = _offsetToX(line,offset);
+ int width = painter.getFontMetrics().charWidth('w');
+
+ if(x < 0) {
+ newHorizontalOffset = Math.min(0,horizontalOffset - x + width + 5);
+ } else if(x + width >= painter.getWidth()) {
+ newHorizontalOffset = horizontalOffset +
+ (painter.getWidth() - x) - width - 5;
+ }
+
+ return setOrigin(newFirstLine,newHorizontalOffset);
+ }
+
+ /**
+ * Converts a line index to a y co-ordinate.
+ * @param line The line
+ */
+ public int lineToY(int line)
+ {
+ FontMetrics fm = painter.getFontMetrics();
+ return (line - firstLine) * fm.getHeight()
+ - (fm.getLeading() + fm.getMaxDescent());
+ }
+
+ /**
+ * Converts a y co-ordinate to a line index.
+ * @param y The y co-ordinate
+ */
+ public int yToLine(int y)
+ {
+ FontMetrics fm = painter.getFontMetrics();
+ int height = fm.getHeight();
+ return Math.max(0,Math.min(getLineCount() - 1,
+ y / height + firstLine));
+ }
+
+ /**
+ * Converts an offset in a line into an x co-ordinate. This is a
+ * slow version that can be used any time.
+ * @param line The line
+ * @param offset The offset, from the start of the line
+ */
+ public final int offsetToX(int line, int offset)
+ {
+ // don't use cached tokens
+ painter.currentLineTokens = null;
+ return _offsetToX(line,offset);
+ }
+
+ /**
+ * Converts an offset in a line into an x co-ordinate. This is a
+ * fast version that should only be used if no changes were made
+ * to the text since the last repaint.
+ * @param line The line
+ * @param offset The offset, from the start of the line
+ */
+ public int _offsetToX(int line, int offset)
+ {
+ TokenMarker tokenMarker = getTokenMarker();
+
+ /* Use painter's cached info for speed */
+ FontMetrics fm = painter.getFontMetrics();
+
+ getLineText(line,lineSegment);
+
+ int segmentOffset = lineSegment.offset;
+ int x = horizontalOffset;
+
+ /* If syntax coloring is disabled, do simple translation */
+ if(tokenMarker == null)
+ {
+ lineSegment.count = offset;
+ return x + Utilities.getTabbedTextWidth(lineSegment,
+ fm,x,painter,0);
+ }
+ /* If syntax coloring is enabled, we have to do this because
+ * tokens can vary in width */
+ else
+ {
+ Token tokens;
+ if(painter.currentLineIndex == line
+ && painter.currentLineTokens != null)
+ tokens = painter.currentLineTokens;
+ else
+ {
+ painter.currentLineIndex = line;
+ tokens = painter.currentLineTokens
+ = tokenMarker.markTokens(lineSegment,line);
+ }
+
+ //Toolkit toolkit = painter.getToolkit();
+ Font defaultFont = painter.getFont();
+ SyntaxStyle[] styles = painter.getStyles();
+
+ for(;;)
+ {
+ byte id = tokens.id;
+ if(id == Token.END)
+ {
+ return x;
+ }
+
+ if(id == Token.NULL)
+ fm = painter.getFontMetrics();
+ else
+ fm = styles[id].getFontMetrics(defaultFont, this);
+
+ int length = tokens.length;
+
+ if(offset + segmentOffset < lineSegment.offset + length)
+ {
+ lineSegment.count = offset - (lineSegment.offset - segmentOffset);
+ return x + Utilities.getTabbedTextWidth(
+ lineSegment,fm,x,painter,0);
+ }
+ else
+ {
+ lineSegment.count = length;
+ x += Utilities.getTabbedTextWidth(
+ lineSegment,fm,x,painter,0);
+ lineSegment.offset += length;
+ }
+ tokens = tokens.next;
+ }
+ }
+ }
+
+ /**
+ * Converts an x co-ordinate to an offset within a line.
+ * @param line The line
+ * @param x The x co-ordinate
+ */
+ public int xToOffset(int line, int x)
+ {
+ TokenMarker tokenMarker = getTokenMarker();
+
+ /* Use painter's cached info for speed */
+ FontMetrics fm = painter.getFontMetrics();
+
+ getLineText(line,lineSegment);
+
+ char[] segmentArray = lineSegment.array;
+ int segmentOffset = lineSegment.offset;
+ int segmentCount = lineSegment.count;
+
+ int width = horizontalOffset;
+
+ if(tokenMarker == null)
+ {
+ for(int i = 0; i < segmentCount; i++)
+ {
+ char c = segmentArray[i + segmentOffset];
+ int charWidth;
+ if(c == '\t')
+ charWidth = (int)painter.nextTabStop(width,i)
+ - width;
+ else
+ charWidth = fm.charWidth(c);
+
+ if(painter.isBlockCaretEnabled())
+ {
+ if(x - charWidth <= width)
+ return i;
+ }
+ else
+ {
+ if(x - charWidth / 2 <= width)
+ return i;
+ }
+
+ width += charWidth;
+ }
+
+ return segmentCount;
+ }
+ else
+ {
+ Token tokens;
+ if(painter.currentLineIndex == line && painter
+ .currentLineTokens != null)
+ tokens = painter.currentLineTokens;
+ else
+ {
+ painter.currentLineIndex = line;
+ tokens = painter.currentLineTokens
+ = tokenMarker.markTokens(lineSegment,line);
+ }
+
+ int offset = 0;
+ //Toolkit toolkit = painter.getToolkit();
+ Font defaultFont = painter.getFont();
+ SyntaxStyle[] styles = painter.getStyles();
+
+ for(;;)
+ {
+ byte id = tokens.id;
+ if(id == Token.END)
+ return offset;
+
+ if(id == Token.NULL)
+ fm = painter.getFontMetrics();
+ else
+ fm = styles[id].getFontMetrics(defaultFont, this);
+
+ int length = tokens.length;
+
+ for(int i = 0; i < length; i++)
+ {
+ char c = segmentArray[segmentOffset + offset + i];
+ int charWidth;
+ if(c == '\t')
+ charWidth = (int)painter.nextTabStop(width,offset + i)
+ - width;
+ else
+ charWidth = fm.charWidth(c);
+
+ if(painter.isBlockCaretEnabled())
+ {
+ if(x - charWidth <= width)
+ return offset + i;
+ }
+ else
+ {
+ if(x - charWidth / 2 <= width)
+ return offset + i;
+ }
+
+ width += charWidth;
+ }
+
+ offset += length;
+ tokens = tokens.next;
+ }
+ }
+ }
+
+ /**
+ * Converts a point to an offset, from the start of the text.
+ * @param x The x co-ordinate of the point
+ * @param y The y co-ordinate of the point
+ */
+ public int xyToOffset(int x, int y)
+ {
+ int line = yToLine(y);
+ int start = getLineStartOffset(line);
+ return start + xToOffset(line,x);
+ }
+
+ /**
+ * Returns the document this text area is editing.
+ */
+ public final SyntaxDocument getDocument()
+ {
+ return document;
+ }
+
+ /**
+ * Sets the document this text area is editing.
+ * @param document The document
+ */
+ public void setDocument(SyntaxDocument document) {
+ if (this.document == document)
+ return;
+ if (this.document != null)
+ this.document.removeDocumentListener(documentHandler);
+ this.document = document;
+
+ document.addDocumentListener(documentHandler);
+
+ select(0, 0);
+ updateScrollBars();
+ painter.repaint();
+ }
+
+
+ /**
+ * Set document with a twist, includes the old caret
+ * and scroll positions, added for p5. [fry]
+ */
+ public void setDocument(SyntaxDocument document,
+ int start, int stop, int scroll) {
+ if (this.document == document)
+ return;
+ if (this.document != null)
+ this.document.removeDocumentListener(documentHandler);
+ this.document = document;
+
+ document.addDocumentListener(documentHandler);
+
+ select(start, stop);
+ updateScrollBars();
+ setScrollPosition(scroll);
+ painter.repaint();
+ }
+
+
+ /**
+ * Returns the document's token marker. Equivalent to calling
+ * getDocument().getTokenMarker().
+ */
+ public final TokenMarker getTokenMarker()
+ {
+ return document.getTokenMarker();
+ }
+
+ /**
+ * Sets the document's token marker. Equivalent to caling
+ * getDocument().setTokenMarker().
+ * @param tokenMarker The token marker
+ */
+ public final void setTokenMarker(TokenMarker tokenMarker)
+ {
+ document.setTokenMarker(tokenMarker);
+ }
+
+ /**
+ * Returns the length of the document. Equivalent to calling
+ * getDocument().getLength().
+ */
+ public final int getDocumentLength()
+ {
+ return document.getLength();
+ }
+
+ /**
+ * Returns the number of lines in the document.
+ */
+ public final int getLineCount()
+ {
+ return document.getDefaultRootElement().getElementCount();
+ }
+
+ /**
+ * Returns the line containing the specified offset.
+ * @param offset The offset
+ */
+ public final int getLineOfOffset(int offset)
+ {
+ return document.getDefaultRootElement().getElementIndex(offset);
+ }
+
+ /**
+ * Returns the start offset of the specified line.
+ * @param line The line
+ * @return The start offset of the specified line, or -1 if the line is
+ * invalid
+ */
+ public int getLineStartOffset(int line)
+ {
+ Element lineElement = document.getDefaultRootElement()
+ .getElement(line);
+ if(lineElement == null)
+ return -1;
+ else
+ return lineElement.getStartOffset();
+ }
+
+ /**
+ * Returns the end offset of the specified line.
+ * @param line The line
+ * @return The end offset of the specified line, or -1 if the line is
+ * invalid.
+ */
+ public int getLineStopOffset(int line)
+ {
+ Element lineElement = document.getDefaultRootElement()
+ .getElement(line);
+ if(lineElement == null)
+ return -1;
+ else
+ return lineElement.getEndOffset();
+ }
+
+ /**
+ * Returns the length of the specified line.
+ * @param line The line
+ */
+ public int getLineLength(int line)
+ {
+ Element lineElement = document.getDefaultRootElement()
+ .getElement(line);
+ if(lineElement == null)
+ return -1;
+ else
+ return lineElement.getEndOffset()
+ - lineElement.getStartOffset() - 1;
+ }
+
+ /**
+ * Returns the entire text of this text area.
+ */
+ public String getText()
+ {
+ try
+ {
+ return document.getText(0,document.getLength());
+ }
+ catch(BadLocationException bl)
+ {
+ bl.printStackTrace();
+ return null;
+ }
+ }
+
+
+ /**
+ * Sets the entire text of this text area.
+ */
+ public void setText(String text)
+ {
+ try {
+ document.beginCompoundEdit();
+ document.remove(0,document.getLength());
+ document.insertString(0,text,null);
+
+ } catch (BadLocationException bl) {
+ bl.printStackTrace();
+
+ } finally {
+ document.endCompoundEdit();
+ }
+ }
+
+
+ /**
+ * Returns the specified substring of the document.
+ * @param start The start offset
+ * @param len The length of the substring
+ * @return The substring, or null if the offsets are invalid
+ */
+ public final String getText(int start, int len)
+ {
+ try
+ {
+ return document.getText(start,len);
+ }
+ catch(BadLocationException bl)
+ {
+ bl.printStackTrace();
+ return null;
+ }
+ }
+
+ /**
+ * Copies the specified substring of the document into a segment.
+ * If the offsets are invalid, the segment will contain a null string.
+ * @param start The start offset
+ * @param len The length of the substring
+ * @param segment The segment
+ */
+ public final void getText(int start, int len, Segment segment)
+ {
+ try
+ {
+ document.getText(start,len,segment);
+ }
+ catch(BadLocationException bl)
+ {
+ bl.printStackTrace();
+ segment.offset = segment.count = 0;
+ }
+ }
+
+ /**
+ * Returns the text on the specified line.
+ * @param lineIndex The line
+ * @return The text, or null if the line is invalid
+ */
+ public final String getLineText(int lineIndex)
+ {
+ int start = getLineStartOffset(lineIndex);
+ return getText(start,getLineStopOffset(lineIndex) - start - 1);
+ }
+
+ /**
+ * Copies the text on the specified line into a segment. If the line
+ * is invalid, the segment will contain a null string.
+ * @param lineIndex The line
+ */
+ public final void getLineText(int lineIndex, Segment segment)
+ {
+ int start = getLineStartOffset(lineIndex);
+ getText(start,getLineStopOffset(lineIndex) - start - 1,segment);
+ }
+
+ /**
+ * Returns the selection start offset.
+ */
+ public final int getSelectionStart()
+ {
+ return selectionStart;
+ }
+
+ /**
+ * Returns the offset where the selection starts on the specified
+ * line.
+ */
+ public int getSelectionStart(int line)
+ {
+ if(line == selectionStartLine)
+ return selectionStart;
+ else if(rectSelect)
+ {
+ Element map = document.getDefaultRootElement();
+ int start = selectionStart - map.getElement(selectionStartLine)
+ .getStartOffset();
+
+ Element lineElement = map.getElement(line);
+ int lineStart = lineElement.getStartOffset();
+ int lineEnd = lineElement.getEndOffset() - 1;
+ return Math.min(lineEnd,lineStart + start);
+ }
+ else
+ return getLineStartOffset(line);
+ }
+
+ /**
+ * Returns the selection start line.
+ */
+ public final int getSelectionStartLine()
+ {
+ return selectionStartLine;
+ }
+
+ /**
+ * Sets the selection start. The new selection will be the new
+ * selection start and the old selection end.
+ * @param selectionStart The selection start
+ * @see #select(int,int)
+ */
+ public final void setSelectionStart(int selectionStart)
+ {
+ select(selectionStart,selectionEnd);
+ }
+
+ /**
+ * Returns the selection end offset.
+ */
+ public final int getSelectionStop()
+ {
+ return selectionEnd;
+ }
+
+ /**
+ * Returns the offset where the selection ends on the specified
+ * line.
+ */
+ public int getSelectionStop(int line)
+ {
+ if(line == selectionEndLine)
+ return selectionEnd;
+ else if(rectSelect)
+ {
+ Element map = document.getDefaultRootElement();
+ int end = selectionEnd - map.getElement(selectionEndLine)
+ .getStartOffset();
+
+ Element lineElement = map.getElement(line);
+ int lineStart = lineElement.getStartOffset();
+ int lineEnd = lineElement.getEndOffset() - 1;
+ return Math.min(lineEnd,lineStart + end);
+ }
+ else
+ return getLineStopOffset(line) - 1;
+ }
+
+ /**
+ * Returns the selection end line.
+ */
+ public final int getSelectionStopLine()
+ {
+ return selectionEndLine;
+ }
+
+ /**
+ * Sets the selection end. The new selection will be the old
+ * selection start and the bew selection end.
+ * @param selectionEnd The selection end
+ * @see #select(int,int)
+ */
+ public final void setSelectionEnd(int selectionEnd)
+ {
+ select(selectionStart,selectionEnd);
+ }
+
+
+ public final boolean isSelectionActive()
+ {
+ return(selectionStart != selectionEnd);
+ }
+
+ /**
+ * Returns the caret position. This will either be the selection
+ * start or the selection end, depending on which direction the
+ * selection was made in.
+ */
+ public final int getCaretPosition()
+ {
+ return (biasLeft ? selectionStart : selectionEnd);
+ }
+
+ /**
+ * Returns the caret line.
+ */
+ public final int getCaretLine()
+ {
+ return (biasLeft ? selectionStartLine : selectionEndLine);
+ }
+
+ /**
+ * Returns the mark position. This will be the opposite selection
+ * bound to the caret position.
+ * @see #getCaretPosition()
+ */
+ public final int getMarkPosition()
+ {
+ return (biasLeft ? selectionEnd : selectionStart);
+ }
+
+ /**
+ * Returns the mark line.
+ */
+ public final int getMarkLine()
+ {
+ return (biasLeft ? selectionEndLine : selectionStartLine);
+ }
+
+ /**
+ * Sets the caret position. The new selection will consist of the
+ * caret position only (hence no text will be selected)
+ * @param caret The caret position
+ * @see #select(int,int)
+ */
+ public final void setCaretPosition(int caret)
+ {
+ select(caret,caret);
+ }
+
+ /**
+ * Selects all text in the document.
+ */
+ public final void selectAll()
+ {
+ select(0,getDocumentLength());
+ }
+
+ /**
+ * Moves the mark to the caret position.
+ */
+ public final void selectNone()
+ {
+ select(getCaretPosition(),getCaretPosition());
+ }
+
+ /**
+ * Selects from the start offset to the end offset. This is the
+ * general selection method used by all other selecting methods.
+ * The caret position will be start if start < end, and end
+ * if end > start.
+ * @param start The start offset
+ * @param end The end offset
+ */
+ public void select(int start, int end)
+ {
+ int newStart, newEnd;
+ boolean newBias;
+ if(start <= end)
+ {
+ newStart = start;
+ newEnd = end;
+ newBias = false;
+ }
+ else
+ {
+ newStart = end;
+ newEnd = start;
+ newBias = true;
+ }
+
+ if(newStart < 0 || newEnd > getDocumentLength())
+ {
+ throw new IllegalArgumentException("Bounds out of"
+ + " range: " + newStart + "," +
+ newEnd);
+ }
+
+ // If the new position is the same as the old, we don't
+ // do all this crap, however we still do the stuff at
+ // the end (clearing magic position, scrolling)
+ if(newStart != selectionStart || newEnd != selectionEnd
+ || newBias != biasLeft)
+ {
+ int newStartLine = getLineOfOffset(newStart);
+ int newEndLine = getLineOfOffset(newEnd);
+
+ if(painter.isBracketHighlightEnabled())
+ {
+ if(bracketLine != -1)
+ painter.invalidateLine(bracketLine);
+ updateBracketHighlight(end);
+ if(bracketLine != -1)
+ painter.invalidateLine(bracketLine);
+ }
+
+ painter.invalidateLineRange(selectionStartLine,selectionEndLine);
+ painter.invalidateLineRange(newStartLine,newEndLine);
+
+ document.addUndoableEdit(new CaretUndo(selectionStart,selectionEnd));
+
+ selectionStart = newStart;
+ selectionEnd = newEnd;
+ selectionStartLine = newStartLine;
+ selectionEndLine = newEndLine;
+ biasLeft = newBias;
+
+ fireCaretEvent();
+ }
+
+ // When the user is typing, etc, we don't want the caret
+ // to blink
+ blink = true;
+ caretTimer.restart();
+
+ // Disable rectangle select if selection start = selection end
+ if(selectionStart == selectionEnd)
+ rectSelect = false;
+
+ // Clear the `magic' caret position used by up/down
+ magicCaret = -1;
+
+ scrollToCaret();
+
+ // notify the line number feller
+ if (editorLineStatus != null) {
+ editorLineStatus.set(selectionStartLine, selectionEndLine);
+ //System.out.println("why " + selectionStartLine + " " + selectionEndLine);
+ //System.out.println(getLineOfOffset(start) + " " +
+ // getLineOfOffset(end));
+ }
+ }
+
+
+ /**
+ * Returns the selected text, or null if no selection is active.
+ */
+ public final String getSelectedText()
+ {
+ if(selectionStart == selectionEnd)
+ return null;
+
+ if(rectSelect)
+ {
+ // Return each row of the selection on a new line
+
+ Element map = document.getDefaultRootElement();
+
+ int start = selectionStart - map.getElement(selectionStartLine)
+ .getStartOffset();
+ int end = selectionEnd - map.getElement(selectionEndLine)
+ .getStartOffset();
+
+ // Certain rectangles satisfy this condition...
+ if(end < start)
+ {
+ int tmp = end;
+ end = start;
+ start = tmp;
+ }
+
+ StringBuffer buf = new StringBuffer();
+ Segment seg = new Segment();
+
+ for(int i = selectionStartLine; i <= selectionEndLine; i++)
+ {
+ Element lineElement = map.getElement(i);
+ int lineStart = lineElement.getStartOffset();
+ int lineEnd = lineElement.getEndOffset() - 1;
+ int lineLen = lineEnd - lineStart;
+
+ lineStart = Math.min(lineStart + start,lineEnd);
+ lineLen = Math.min(end - start,lineEnd - lineStart);
+
+ getText(lineStart,lineLen,seg);
+ buf.append(seg.array,seg.offset,seg.count);
+
+ if(i != selectionEndLine)
+ buf.append('\n');
+ }
+
+ return buf.toString();
+ }
+ else
+ {
+ return getText(selectionStart,
+ selectionEnd - selectionStart);
+ }
+ }
+
+ /**
+ * Replaces the selection with the specified text.
+ * @param selectedText The replacement text for the selection
+ */
+ public void setSelectedText(String selectedText)
+ {
+ if(!editable)
+ {
+ throw new InternalError("Text component"
+ + " read only");
+ }
+
+ document.beginCompoundEdit();
+
+ try
+ {
+ if(rectSelect)
+ {
+ Element map = document.getDefaultRootElement();
+
+ int start = selectionStart - map.getElement(selectionStartLine)
+ .getStartOffset();
+ int end = selectionEnd - map.getElement(selectionEndLine)
+ .getStartOffset();
+
+ // Certain rectangles satisfy this condition...
+ if(end < start)
+ {
+ int tmp = end;
+ end = start;
+ start = tmp;
+ }
+
+ int lastNewline = 0;
+ int currNewline = 0;
+
+ for(int i = selectionStartLine; i <= selectionEndLine; i++)
+ {
+ Element lineElement = map.getElement(i);
+ int lineStart = lineElement.getStartOffset();
+ int lineEnd = lineElement.getEndOffset() - 1;
+ int rectStart = Math.min(lineEnd,lineStart + start);
+
+ document.remove(rectStart,Math.min(lineEnd - rectStart,
+ end - start));
+
+ if(selectedText == null)
+ continue;
+
+ currNewline = selectedText.indexOf('\n',lastNewline);
+ if(currNewline == -1)
+ currNewline = selectedText.length();
+
+ document.insertString(rectStart,selectedText
+ .substring(lastNewline,currNewline),null);
+
+ lastNewline = Math.min(selectedText.length(),
+ currNewline + 1);
+ }
+
+ if(selectedText != null &&
+ currNewline != selectedText.length())
+ {
+ int offset = map.getElement(selectionEndLine)
+ .getEndOffset() - 1;
+ document.insertString(offset,"\n",null);
+ document.insertString(offset + 1,selectedText
+ .substring(currNewline + 1),null);
+ }
+ }
+ else
+ {
+ document.remove(selectionStart,
+ selectionEnd - selectionStart);
+ if(selectedText != null)
+ {
+ document.insertString(selectionStart,
+ selectedText,null);
+ }
+ }
+ }
+ catch(BadLocationException bl)
+ {
+ bl.printStackTrace();
+ throw new InternalError("Cannot replace"
+ + " selection");
+ }
+ // No matter what happends... stops us from leaving document
+ // in a bad state
+ finally
+ {
+ document.endCompoundEdit();
+ }
+
+ setCaretPosition(selectionEnd);
+ }
+
+ /**
+ * Returns true if this text area is editable, false otherwise.
+ */
+ public final boolean isEditable()
+ {
+ return editable;
+ }
+
+ /**
+ * Sets if this component is editable.
+ * @param editable True if this text area should be editable,
+ * false otherwise
+ */
+ public final void setEditable(boolean editable)
+ {
+ this.editable = editable;
+ }
+
+ /**
+ * Returns the right click popup menu.
+ */
+ public final JPopupMenu getRightClickPopup()
+ {
+ return popup;
+ }
+
+ /**
+ * Sets the right click popup menu.
+ * @param popup The popup
+ */
+ //public final void setRightClickPopup(EditPopupMenu popup)
+ public final void setRightClickPopup(JPopupMenu popup)
+ {
+ this.popup = popup;
+ }
+
+
+ /**
+ * Returns the `magic' caret position. This can be used to preserve
+ * the column position when moving up and down lines.
+ */
+ public final int getMagicCaretPosition()
+ {
+ return magicCaret;
+ }
+
+ /**
+ * Sets the `magic' caret position. This can be used to preserve
+ * the column position when moving up and down lines.
+ * @param magicCaret The magic caret position
+ */
+ public final void setMagicCaretPosition(int magicCaret)
+ {
+ this.magicCaret = magicCaret;
+ }
+
+ /**
+ * Similar to setSelectedText(), but overstrikes the
+ * appropriate number of characters if overwrite mode is enabled.
+ * @param str The string
+ * @see #setSelectedText(String)
+ * @see #isOverwriteEnabled()
+ */
+ public void overwriteSetSelectedText(String str)
+ {
+ // Don't overstrike if there is a selection
+ if(!overwrite || selectionStart != selectionEnd)
+ {
+ setSelectedText(str);
+ return;
+ }
+
+ // Don't overstrike if we're on the end of
+ // the line
+ int caret = getCaretPosition();
+ int caretLineEnd = getLineStopOffset(getCaretLine());
+ if(caretLineEnd - caret <= str.length())
+ {
+ setSelectedText(str);
+ return;
+ }
+
+ document.beginCompoundEdit();
+
+ try
+ {
+ document.remove(caret,str.length());
+ document.insertString(caret,str,null);
+ }
+ catch(BadLocationException bl)
+ {
+ bl.printStackTrace();
+ }
+ finally
+ {
+ document.endCompoundEdit();
+ }
+ }
+
+ /**
+ * Returns true if overwrite mode is enabled, false otherwise.
+ */
+ public final boolean isOverwriteEnabled()
+ {
+ return overwrite;
+ }
+
+ /**
+ * Sets if overwrite mode should be enabled.
+ * @param overwrite True if overwrite mode should be enabled,
+ * false otherwise.
+ */
+ public final void setOverwriteEnabled(boolean overwrite)
+ {
+ this.overwrite = overwrite;
+ painter.invalidateSelectedLines();
+ }
+
+ /**
+ * Returns true if the selection is rectangular, false otherwise.
+ */
+ public final boolean isSelectionRectangular()
+ {
+ return rectSelect;
+ }
+
+ /**
+ * Sets if the selection should be rectangular.
+ * @param rectSelect True if the selection should be rectangular,
+ * false otherwise.
+ */
+ public final void setSelectionRectangular(boolean rectSelect)
+ {
+ this.rectSelect = rectSelect;
+ painter.invalidateSelectedLines();
+ }
+
+ /**
+ * Returns the position of the highlighted bracket (the bracket
+ * matching the one before the caret)
+ */
+ public final int getBracketPosition()
+ {
+ return bracketPosition;
+ }
+
+ /**
+ * Returns the line of the highlighted bracket (the bracket
+ * matching the one before the caret)
+ */
+ public final int getBracketLine()
+ {
+ return bracketLine;
+ }
+
+ /**
+ * Adds a caret change listener to this text area.
+ * @param listener The listener
+ */
+ public final void addCaretListener(CaretListener listener)
+ {
+ eventListenerList.add(CaretListener.class,listener);
+ }
+
+ /**
+ * Removes a caret change listener from this text area.
+ * @param listener The listener
+ */
+ public final void removeCaretListener(CaretListener listener)
+ {
+ eventListenerList.remove(CaretListener.class,listener);
+ }
+
+ /**
+ * Deletes the selected text from the text area and places it
+ * into the clipboard.
+ */
+ public void cut()
+ {
+ if(editable)
+ {
+ copy();
+ setSelectedText("");
+ }
+ }
+
+ /**
+ * Places the selected text into the clipboard.
+ */
+ public void copy()
+ {
+ if(selectionStart != selectionEnd)
+ {
+ Clipboard clipboard = getToolkit().getSystemClipboard();
+
+ String selection = getSelectedText();
+
+ int repeatCount = inputHandler.getRepeatCount();
+ StringBuffer buf = new StringBuffer();
+ for(int i = 0; i < repeatCount; i++)
+ buf.append(selection);
+
+ clipboard.setContents(new StringSelection(buf.toString()),null);
+ }
+ }
+
+ /**
+ * Inserts the clipboard contents into the text.
+ */
+ public void paste() {
+ if (editable) {
+ Clipboard clipboard = getToolkit().getSystemClipboard();
+ try {
+ // The MacOS MRJ doesn't convert \r to \n, so do it here
+ String selection = ((String)clipboard.getContents(this).getTransferData(DataFlavor.stringFlavor)).replace('\r','\n');
+
+ // particularly on macosx when pasting from safari,
+ // replace unicode x00A0 (non-breaking space)
+ // with just a plain space. [fry 030929]
+ selection = selection.replace('\u00A0', ' ');
+
+ int repeatCount = inputHandler.getRepeatCount();
+ StringBuffer buf = new StringBuffer();
+ for (int i = 0; i < repeatCount; i++)
+ buf.append(selection);
+ selection = buf.toString();
+ setSelectedText(selection);
+
+ } catch(Exception e) {
+ getToolkit().beep();
+ System.err.println("Clipboard does not contain a string");
+ }
+ }
+ }
+
+ /**
+ * Called by the AWT when this component is removed from it's parent.
+ * This stops clears the currently focused component.
+ */
+ public void removeNotify()
+ {
+ super.removeNotify();
+ if(focusedComponent == this)
+ focusedComponent = null;
+ }
+
+ /**
+ * Forwards key events directly to the input handler.
+ * This is slightly faster than using a KeyListener
+ * because some Swing overhead is avoided.
+ */
+ public EditorListener editorListener;
+
+ /**
+ * The component that tracks the current line number.
+ */
+ public EditorLineStatus editorLineStatus;
+
+
+ public void processKeyEvent(KeyEvent evt) {
+ // this had to be added in Processing 007X, because the menu key
+ // events weren't making it up to the frame.
+ super.processKeyEvent(evt);
+
+ //System.out.println("jedittextarea: " + evt);
+ //System.out.println();
+ if (inputHandler == null) return;
+
+ switch(evt.getID()) {
+ case KeyEvent.KEY_TYPED:
+ if ((editorListener == null) || !editorListener.keyTyped(evt)) {
+ inputHandler.keyTyped(evt);
+ }
+ break;
+ case KeyEvent.KEY_PRESSED:
+ if ((editorListener == null) || !editorListener.keyPressed(evt)) {
+ inputHandler.keyPressed(evt);
+ }
+ break;
+ case KeyEvent.KEY_RELEASED:
+ inputHandler.keyReleased(evt);
+ break;
+ }
+ }
+
+ // protected members
+ protected static String CENTER = "center";
+ protected static String RIGHT = "right";
+ protected static String BOTTOM = "bottom";
+
+ protected static JEditTextArea focusedComponent;
+ protected static Timer caretTimer;
+
+ protected TextAreaPainter painter;
+
+ //protected EditPopupMenu popup;
+ protected JPopupMenu popup;
+
+ protected EventListenerList eventListenerList;
+ protected MutableCaretEvent caretEvent;
+
+ protected boolean caretBlinks;
+ protected boolean caretVisible;
+ protected boolean blink;
+
+ protected boolean editable;
+
+ protected int firstLine;
+ protected int visibleLines;
+ protected int electricScroll;
+
+ protected int horizontalOffset;
+
+ protected JScrollBar vertical;
+ protected JScrollBar horizontal;
+ protected boolean scrollBarsInitialized;
+
+ protected InputHandler inputHandler;
+ protected SyntaxDocument document;
+ protected DocumentHandler documentHandler;
+
+ protected Segment lineSegment;
+
+ protected int selectionStart;
+ protected int selectionStartLine;
+ protected int selectionEnd;
+ protected int selectionEndLine;
+ protected boolean biasLeft;
+
+ protected int bracketPosition;
+ protected int bracketLine;
+
+ protected int magicCaret;
+ protected boolean overwrite;
+ protected boolean rectSelect;
+
+
+ protected void fireCaretEvent()
+ {
+ Object[] listeners = eventListenerList.getListenerList();
+ for(int i = listeners.length - 2; i >= 0; i--)
+ {
+ if(listeners[i] == CaretListener.class)
+ {
+ ((CaretListener)listeners[i+1]).caretUpdate(caretEvent);
+ }
+ }
+ }
+
+ protected void updateBracketHighlight(int newCaretPosition)
+ {
+ if(newCaretPosition == 0)
+ {
+ bracketPosition = bracketLine = -1;
+ return;
+ }
+
+ try
+ {
+ int offset = TextUtilities.findMatchingBracket(
+ document,newCaretPosition - 1);
+ if(offset != -1)
+ {
+ bracketLine = getLineOfOffset(offset);
+ bracketPosition = offset - getLineStartOffset(bracketLine);
+ return;
+ }
+ }
+ catch(BadLocationException bl)
+ {
+ bl.printStackTrace();
+ }
+
+ bracketLine = bracketPosition = -1;
+ }
+
+ protected void documentChanged(DocumentEvent evt)
+ {
+ DocumentEvent.ElementChange ch =
+ evt.getChange(document.getDefaultRootElement());
+
+ int count;
+ if(ch == null)
+ count = 0;
+ else
+ count = ch.getChildrenAdded().length -
+ ch.getChildrenRemoved().length;
+
+ int line = getLineOfOffset(evt.getOffset());
+ if(count == 0)
+ {
+ painter.invalidateLine(line);
+ }
+ // do magic stuff
+ else if(line < firstLine)
+ {
+ setFirstLine(firstLine + count);
+ }
+ // end of magic stuff
+ else
+ {
+ painter.invalidateLineRange(line,firstLine + visibleLines);
+ updateScrollBars();
+ }
+ }
+
+ class ScrollLayout implements LayoutManager
+ {
+ //final int LEFT_EXTRA = 5;
+
+ public void addLayoutComponent(String name, Component comp)
+ {
+ if(name.equals(CENTER))
+ center = comp;
+ else if(name.equals(RIGHT))
+ right = comp;
+ else if(name.equals(BOTTOM))
+ bottom = comp;
+ else if(name.equals(LEFT_OF_SCROLLBAR))
+ leftOfScrollBar.addElement(comp);
+ }
+
+ public void removeLayoutComponent(Component comp)
+ {
+ if(center == comp)
+ center = null;
+ if(right == comp)
+ right = null;
+ if(bottom == comp)
+ bottom = null;
+ else
+ leftOfScrollBar.removeElement(comp);
+ }
+
+ public Dimension preferredLayoutSize(Container parent)
+ {
+ Dimension dim = new Dimension();
+ Insets insets = getInsets();
+ dim.width = insets.left + insets.right;
+ dim.height = insets.top + insets.bottom;
+
+ Dimension centerPref = center.getPreferredSize();
+ dim.width += centerPref.width;
+ dim.height += centerPref.height;
+ Dimension rightPref = right.getPreferredSize();
+ dim.width += rightPref.width;
+ Dimension bottomPref = bottom.getPreferredSize();
+ dim.height += bottomPref.height;
+
+ return dim;
+ }
+
+ public Dimension minimumLayoutSize(Container parent)
+ {
+ Dimension dim = new Dimension();
+ Insets insets = getInsets();
+ dim.width = insets.left + insets.right;
+ dim.height = insets.top + insets.bottom;
+
+ Dimension centerPref = center.getMinimumSize();
+ dim.width += centerPref.width;
+ dim.height += centerPref.height;
+ Dimension rightPref = right.getMinimumSize();
+ dim.width += rightPref.width;
+ Dimension bottomPref = bottom.getMinimumSize();
+ dim.height += bottomPref.height;
+
+ dim.height += 5;
+
+ return dim;
+ }
+
+ public void layoutContainer(Container parent)
+ {
+ Dimension size = parent.getSize();
+ Insets insets = parent.getInsets();
+ int itop = insets.top;
+ int ileft = insets.left;
+ int ibottom = insets.bottom;
+ int iright = insets.right;
+
+ int rightWidth = right.getPreferredSize().width;
+ int bottomHeight = bottom.getPreferredSize().height;
+ int centerWidth = size.width - rightWidth - ileft - iright;
+ int centerHeight = size.height - bottomHeight - itop - ibottom;
+
+ center.setBounds(ileft, // + LEFT_EXTRA,
+ itop,
+ centerWidth, // - LEFT_EXTRA,
+ centerHeight);
+
+ right.setBounds(ileft + centerWidth,
+ itop,
+ rightWidth,
+ centerHeight);
+
+ // Lay out all status components, in order
+ Enumeration status = leftOfScrollBar.elements();
+ while (status.hasMoreElements()) {
+ Component comp = (Component)status.nextElement();
+ Dimension dim = comp.getPreferredSize();
+ comp.setBounds(ileft,
+ itop + centerHeight,
+ dim.width,
+ bottomHeight);
+ ileft += dim.width;
+ }
+
+ bottom.setBounds(ileft,
+ itop + centerHeight,
+ size.width - rightWidth - ileft - iright,
+ bottomHeight);
+ }
+
+ // private members
+ private Component center;
+ private Component right;
+ private Component bottom;
+ private Vector leftOfScrollBar = new Vector();
+ }
+
+ static class CaretBlinker implements ActionListener
+ {
+ public void actionPerformed(ActionEvent evt)
+ {
+ if(focusedComponent != null
+ && focusedComponent.hasFocus())
+ focusedComponent.blinkCaret();
+ }
+ }
+
+ class MutableCaretEvent extends CaretEvent
+ {
+ MutableCaretEvent()
+ {
+ super(JEditTextArea.this);
+ }
+
+ public int getDot()
+ {
+ return getCaretPosition();
+ }
+
+ public int getMark()
+ {
+ return getMarkPosition();
+ }
+ }
+
+/*
+#ifdef JDK14
+ class WheelHandler implements MouseWheelListener {
+
+ public void mouseWheelMoved(MouseWheelEvent e) {
+ if (!scrollBarsInitialized) return;
+
+ int amt = e.getWheelRotation();
+ //System.out.println(amt);
+ vertical.setValue(vertical.getValue() + amt * wheelMultiplier);
+ }
+ }
+#endif
+*/
+
+ class AdjustHandler implements AdjustmentListener
+ {
+ public void adjustmentValueChanged(final AdjustmentEvent evt)
+ {
+ if(!scrollBarsInitialized)
+ return;
+
+ // If this is not done, mousePressed events accumilate
+ // and the result is that scrolling doesn't stop after
+ // the mouse is released
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run()
+ {
+ if(evt.getAdjustable() == vertical)
+ setFirstLine(vertical.getValue());
+ else
+ setHorizontalOffset(-horizontal.getValue());
+ }
+ });
+ }
+ }
+
+ class ComponentHandler extends ComponentAdapter
+ {
+ public void componentResized(ComponentEvent evt)
+ {
+ recalculateVisibleLines();
+ scrollBarsInitialized = true;
+ }
+ }
+
+ class DocumentHandler implements DocumentListener
+ {
+ public void insertUpdate(DocumentEvent evt)
+ {
+ documentChanged(evt);
+
+ int offset = evt.getOffset();
+ int length = evt.getLength();
+
+ int newStart;
+ int newEnd;
+
+ if (selectionStart > offset ||
+ (selectionStart == selectionEnd && selectionStart == offset))
+ newStart = selectionStart + length;
+ else
+ newStart = selectionStart;
+
+ if(selectionEnd >= offset)
+ newEnd = selectionEnd + length;
+ else
+ newEnd = selectionEnd;
+
+ select(newStart,newEnd);
+ }
+
+ public void removeUpdate(DocumentEvent evt)
+ {
+ documentChanged(evt);
+
+ int offset = evt.getOffset();
+ int length = evt.getLength();
+
+ int newStart;
+ int newEnd;
+
+ if(selectionStart > offset)
+ {
+ if(selectionStart > offset + length)
+ newStart = selectionStart - length;
+ else
+ newStart = offset;
+ }
+ else
+ newStart = selectionStart;
+
+ if(selectionEnd > offset)
+ {
+ if(selectionEnd > offset + length)
+ newEnd = selectionEnd - length;
+ else
+ newEnd = offset;
+ }
+ else
+ newEnd = selectionEnd;
+
+ select(newStart,newEnd);
+ }
+
+ public void changedUpdate(DocumentEvent evt)
+ {
+ }
+ }
+
+ class DragHandler implements MouseMotionListener
+ {
+ public void mouseDragged(MouseEvent evt)
+ {
+ if (popup != null && popup.isVisible()) return;
+
+ setSelectionRectangular((evt.getModifiers()
+ & InputEvent.CTRL_MASK) != 0);
+ select(getMarkPosition(),xyToOffset(evt.getX(),evt.getY()));
+ }
+
+ public void mouseMoved(MouseEvent evt) {}
+ }
+
+ class FocusHandler implements FocusListener
+ {
+ public void focusGained(FocusEvent evt)
+ {
+ //System.out.println("JEditTextArea: focusGained");
+ setCaretVisible(true);
+ focusedComponent = JEditTextArea.this;
+ }
+
+ public void focusLost(FocusEvent evt)
+ {
+ //System.out.println("JEditTextArea: focusLost");
+ setCaretVisible(false);
+ focusedComponent = null;
+ }
+ }
+
+ class MouseHandler extends MouseAdapter
+ {
+ public void mousePressed(MouseEvent evt)
+ {
+ requestFocus();
+
+ // Focus events not fired sometimes?
+ setCaretVisible(true);
+ focusedComponent = JEditTextArea.this;
+
+ // isPopupTrigger wasn't working for danh on windows
+ boolean trigger = (evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0;
+ // but it's required for macosx, since control-click does
+ // the same thing as a right-mouse click
+ if (!trigger && evt.isPopupTrigger()) trigger = true;
+
+ if (trigger && (popup != null)) {
+ popup.show(painter,evt.getX(),evt.getY());
+ return;
+ }
+
+ int line = yToLine(evt.getY());
+ int offset = xToOffset(line,evt.getX());
+ int dot = getLineStartOffset(line) + offset;
+
+ switch(evt.getClickCount()) {
+
+ case 1:
+ doSingleClick(evt,line,offset,dot);
+ break;
+
+ case 2:
+ // It uses the bracket matching stuff, so
+ // it can throw a BLE
+ try {
+ doDoubleClick(evt,line,offset,dot);
+ } catch(BadLocationException bl) {
+ bl.printStackTrace();
+ }
+ break;
+
+ case 3:
+ doTripleClick(evt,line,offset,dot);
+ break;
+ }
+ }
+
+
+ private void doSingleClick(MouseEvent evt, int line,
+ int offset, int dot) {
+ if ((evt.getModifiers() & InputEvent.SHIFT_MASK) != 0) {
+ rectSelect = (evt.getModifiers() & InputEvent.CTRL_MASK) != 0;
+ select(getMarkPosition(),dot);
+ } else {
+ setCaretPosition(dot);
+ }
+ }
+
+
+ private void doDoubleClick(MouseEvent evt, int line,
+ int offset, int dot) throws BadLocationException
+ {
+ // Ignore empty lines
+ if (getLineLength(line) == 0)
+ return;
+
+ try {
+ int bracket = TextUtilities.findMatchingBracket(document,
+ Math.max(0,dot - 1));
+ if (bracket != -1) {
+ int mark = getMarkPosition();
+ // Hack
+ if (bracket > mark) {
+ bracket++;
+ mark--;
+ }
+ select(mark,bracket);
+ return;
+ }
+ } catch(BadLocationException bl) {
+ bl.printStackTrace();
+ }
+
+ String noWordSep = (String)document.getProperty("noWordSep");
+ if(noWordSep == null)
+ noWordSep = "";
+
+ // Ok, it's not a bracket... select the word
+ String lineText = getLineText(line);
+
+ int wordStart = 0;
+ int wordEnd = lineText.length();
+
+ char ch = lineText.charAt(Math.max(0,offset - 1));
+
+ // special case for whitespace (fry 0122, bug #348)
+ // this is really nasty.. turns out that double-clicking any non-letter
+ // or digit char gets lumped together.. sooo, this quickly gets messy,
+ // because really it needs to check whether the chars are of the same
+ // type.. so a double space or double - might be grouped together,
+ // but what about a +=1? do + and - get grouped but not the 1? blech,
+ // coming back to this later. it's not a difficult fix, just a
+ // time-consuming one to track down all the proper cases.
+ /*
+ if (ch == ' ') {
+ //System.out.println("yeehaa");
+
+ for(int i = offset - 1; i >= 0; i--) {
+ if (lineText.charAt(i) == ' ') {
+ wordStart = i;
+ } else {
+ break;
+ }
+ }
+ for(int i = offset; i < lineText.length(); i++) {
+ if (lineText.charAt(i) == ' ') {
+ wordEnd = i + 1;
+ } else {
+ break;
+ }
+ }
+
+ } else {
+ */
+
+ // If the user clicked on a non-letter char,
+ // we select the surrounding non-letters
+ boolean selectNoLetter = (!Character.isLetterOrDigit(ch)
+ && noWordSep.indexOf(ch) == -1);
+
+ for(int i = offset - 1; i >= 0; i--) {
+ ch = lineText.charAt(i);
+ if (selectNoLetter ^ (!Character.isLetterOrDigit(ch) &&
+ noWordSep.indexOf(ch) == -1)) {
+ wordStart = i + 1;
+ break;
+ }
+ }
+
+ for(int i = offset; i < lineText.length(); i++) {
+ ch = lineText.charAt(i);
+ if(selectNoLetter ^ (!Character.isLetterOrDigit(ch) &&
+ noWordSep.indexOf(ch) == -1)) {
+ wordEnd = i;
+ break;
+ }
+ }
+ //}
+
+ int lineStart = getLineStartOffset(line);
+ select(lineStart + wordStart,lineStart + wordEnd);
+
+ /*
+ String lineText = getLineText(line);
+ String noWordSep = (String)document.getProperty("noWordSep");
+ int wordStart = TextUtilities.findWordStart(lineText,offset,noWordSep);
+ int wordEnd = TextUtilities.findWordEnd(lineText,offset,noWordSep);
+
+ int lineStart = getLineStartOffset(line);
+ select(lineStart + wordStart,lineStart + wordEnd);
+ */
+ }
+
+ private void doTripleClick(MouseEvent evt, int line,
+ int offset, int dot)
+ {
+ select(getLineStartOffset(line),getLineStopOffset(line)-1);
+ }
+ }
+
+ class CaretUndo extends AbstractUndoableEdit
+ {
+ private int start;
+ private int end;
+
+ CaretUndo(int start, int end)
+ {
+ this.start = start;
+ this.end = end;
+ }
+
+ public boolean isSignificant()
+ {
+ return false;
+ }
+
+ public String getPresentationName()
+ {
+ return "caret move";
+ }
+
+ public void undo() throws CannotUndoException
+ {
+ super.undo();
+
+ select(start,end);
+ }
+
+ public void redo() throws CannotRedoException
+ {
+ super.redo();
+
+ select(start,end);
+ }
+
+ public boolean addEdit(UndoableEdit edit)
+ {
+ if(edit instanceof CaretUndo)
+ {
+ CaretUndo cedit = (CaretUndo)edit;
+ start = cedit.start;
+ end = cedit.end;
+ cedit.die();
+
+ return true;
+ }
+ else
+ return false;
+ }
+ }
+
+ static
+ {
+ caretTimer = new Timer(500,new CaretBlinker());
+ caretTimer.setInitialDelay(500);
+ caretTimer.start();
+ }
+}
diff --git a/app/src/processing/app/syntax/KeywordMap.java b/app/src/processing/app/syntax/KeywordMap.java
new file mode 100644
index 000000000..065d92b3f
--- /dev/null
+++ b/app/src/processing/app/syntax/KeywordMap.java
@@ -0,0 +1,140 @@
+/*
+ * KeywordMap.java - Fast keyword->id map
+ * Copyright (C) 1998, 1999 Slava Pestov
+ * Copyright (C) 1999 Mike Dillon
+ *
+ * You may use and modify this package for any purpose. Redistribution is
+ * permitted, in both source and binary form, provided that this notice
+ * remains intact in all source distributions of this package.
+ */
+
+package processing.app.syntax;
+
+import javax.swing.text.Segment;
+
+/**
+ * A KeywordMap is similar to a hashtable in that it maps keys
+ * to values. However, the `keys' are Swing segments. This allows lookups of
+ * text substrings without the overhead of creating a new string object.
+ *
+ * This class is used by CTokenMarker to map keywords to ids.
+ *
+ * @author Slava Pestov, Mike Dillon
+ * @version $Id: KeywordMap.java 2050 2006-03-11 00:50:01Z fry $
+ */
+public class KeywordMap
+{
+ /**
+ * Creates a new KeywordMap.
+ * @param ignoreCase True if keys are case insensitive
+ */
+ public KeywordMap(boolean ignoreCase)
+ {
+ this(ignoreCase, 52);
+ this.ignoreCase = ignoreCase;
+ }
+
+ /**
+ * Creates a new KeywordMap.
+ * @param ignoreCase True if the keys are case insensitive
+ * @param mapLength The number of `buckets' to create.
+ * A value of 52 will give good performance for most maps.
+ */
+ public KeywordMap(boolean ignoreCase, int mapLength)
+ {
+ this.mapLength = mapLength;
+ this.ignoreCase = ignoreCase;
+ map = new Keyword[mapLength];
+ }
+
+ /**
+ * Looks up a key.
+ * @param text The text segment
+ * @param offset The offset of the substring within the text segment
+ * @param length The length of the substring
+ */
+ public byte lookup(Segment text, int offset, int length)
+ {
+ if(length == 0)
+ return Token.NULL;
+ Keyword k = map[getSegmentMapKey(text, offset, length)];
+ while(k != null)
+ {
+ if(length != k.keyword.length)
+ {
+ k = k.next;
+ continue;
+ }
+ if(SyntaxUtilities.regionMatches(ignoreCase,text,offset,
+ k.keyword))
+ return k.id;
+ k = k.next;
+ }
+ return Token.NULL;
+ }
+
+ /**
+ * Adds a key-value mapping.
+ * @param keyword The key
+ * @param id The value
+ */
+ public void add(String keyword, byte id)
+ {
+ int key = getStringMapKey(keyword);
+ map[key] = new Keyword(keyword.toCharArray(),id,map[key]);
+ }
+
+ /**
+ * Returns true if the keyword map is set to be case insensitive,
+ * false otherwise.
+ */
+ public boolean getIgnoreCase()
+ {
+ return ignoreCase;
+ }
+
+ /**
+ * Sets if the keyword map should be case insensitive.
+ * @param ignoreCase True if the keyword map should be case
+ * insensitive, false otherwise
+ */
+ public void setIgnoreCase(boolean ignoreCase)
+ {
+ this.ignoreCase = ignoreCase;
+ }
+
+ // protected members
+ protected int mapLength;
+
+ protected int getStringMapKey(String s)
+ {
+ return (Character.toUpperCase(s.charAt(0)) +
+ Character.toUpperCase(s.charAt(s.length()-1)))
+ % mapLength;
+ }
+
+ protected int getSegmentMapKey(Segment s, int off, int len)
+ {
+ return (Character.toUpperCase(s.array[off]) +
+ Character.toUpperCase(s.array[off + len - 1]))
+ % mapLength;
+ }
+
+ // private members
+ class Keyword
+ {
+ public Keyword(char[] keyword, byte id, Keyword next)
+ {
+ this.keyword = keyword;
+ this.id = id;
+ this.next = next;
+ }
+
+ public char[] keyword;
+ public byte id;
+ public Keyword next;
+ }
+
+ private Keyword[] map;
+ private boolean ignoreCase;
+}
diff --git a/app/src/processing/app/syntax/PdeKeywords.java b/app/src/processing/app/syntax/PdeKeywords.java
new file mode 100644
index 000000000..610a1a995
--- /dev/null
+++ b/app/src/processing/app/syntax/PdeKeywords.java
@@ -0,0 +1,122 @@
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+/*
+ PdeKeywords - handles text coloring and links to html reference
+ Part of the Processing project - http://processing.org
+
+ Copyright (c) 2004-06 Ben Fry and Casey Reas
+ Copyright (c) 2001-04 Massachusetts Institute of Technology
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+package processing.app.syntax;
+
+import processing.app.*;
+
+import java.io.*;
+import java.util.*;
+
+
+public class PdeKeywords extends CTokenMarker {
+
+ // lookup table for the TokenMarker subclass, handles coloring
+ static KeywordMap keywordColoring;
+
+ // lookup table that maps keywords to their html reference pages
+ static Hashtable keywordToReference;
+
+
+ public PdeKeywords() {
+ super(false, getKeywords());
+ }
+
+
+ /**
+ * Handles loading of keywords file.
+ *
+ * Uses getKeywords() method because that's part of the
+ * TokenMarker classes.
+ *
+ * It is recommended that a # sign be used for comments
+ * inside keywords.txt.
+ */
+ static public KeywordMap getKeywords() {
+ if (keywordColoring == null) {
+ try {
+ keywordColoring = new KeywordMap(false);
+ keywordToReference = new Hashtable();
+
+ InputStream input = Base.getLibStream("keywords.txt");
+ InputStreamReader isr = new InputStreamReader(input);
+ BufferedReader reader = new BufferedReader(isr);
+
+ String line = null;
+ while ((line = reader.readLine()) != null) {
+ //System.out.println("line is " + line);
+ // in case there's any garbage on the line
+ //if (line.trim().length() == 0) continue;
+
+ String pieces[] = processing.core.PApplet.split(line, '\t');
+ if (pieces.length >= 2) {
+ //int tab = line.indexOf('\t');
+ // any line with no tab is ignored
+ // meaning that a comment is any line without a tab
+ //if (tab == -1) continue;
+
+ String keyword = pieces[0].trim();
+ //String keyword = line.substring(0, tab).trim();
+ //String second = line.substring(tab + 1);
+ //tab = second.indexOf('\t');
+ //String coloring = second.substring(0, tab).trim();
+ //String htmlFilename = second.substring(tab + 1).trim();
+ String coloring = pieces[1].trim();
+
+ if (coloring.length() > 0) {
+ // text will be KEYWORD or LITERAL
+ boolean isKey = (coloring.charAt(0) == 'K');
+ // KEYWORD1 -> 0, KEYWORD2 -> 1, etc
+ int num = coloring.charAt(coloring.length() - 1) - '1';
+ byte id = (byte)
+ ((isKey ? Token.KEYWORD1 : Token.LITERAL1) + num);
+ //System.out.println("got " + (isKey ? "keyword" : "literal") +
+ // (num+1) + " for " + keyword);
+ keywordColoring.add(keyword, id);
+ }
+ if (pieces.length >= 3) {
+ String htmlFilename = pieces[2].trim();
+ if (htmlFilename.length() > 0) {
+ keywordToReference.put(keyword, htmlFilename);
+ }
+ }
+ }
+ }
+ reader.close();
+
+ } catch (Exception e) {
+ Base.showError("Problem loading keywords",
+ "Could not load keywords.txt,\n" +
+ "please re-install Processing.", e);
+ System.exit(1);
+ }
+ }
+ return keywordColoring;
+ }
+
+
+ static public String getReference(String keyword) {
+ return (String) keywordToReference.get(keyword);
+ }
+}
diff --git a/app/src/processing/app/syntax/PdeTextAreaDefaults.java b/app/src/processing/app/syntax/PdeTextAreaDefaults.java
new file mode 100644
index 000000000..a2dda2b78
--- /dev/null
+++ b/app/src/processing/app/syntax/PdeTextAreaDefaults.java
@@ -0,0 +1,192 @@
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+/*
+ PdeTextAreaDefaults - grabs font/color settings for the editor
+ Part of the Processing project - http://processing.org
+
+ Copyright (c) 2004-06 Ben Fry and Casey Reas
+ Copyright (c) 2001-03 Massachusetts Institute of Technology
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+package processing.app.syntax;
+
+import processing.app.*;
+
+
+public class PdeTextAreaDefaults extends TextAreaDefaults {
+
+ public PdeTextAreaDefaults() {
+
+ inputHandler = new DefaultInputHandler();
+ //inputHandler.addDefaultKeyBindings(); // 0122
+
+ // use option on mac for things that are ctrl on windows/linux
+ String mod = Base.isMacOS() ? "A" : "C";
+
+ // right now, ctrl-up/down is select up/down, but mod should be
+ // used instead, because the mac expects it to be option(alt)
+
+ inputHandler.addKeyBinding("BACK_SPACE", InputHandler.BACKSPACE);
+ inputHandler.addKeyBinding("DELETE", InputHandler.DELETE);
+
+ //inputHandler.addKeyBinding("S+BACK_SPACE", InputHandler.BACKSPACE);
+ // for 0122, shift-backspace is delete
+ inputHandler.addKeyBinding("S+BACK_SPACE", InputHandler.DELETE);
+ inputHandler.addKeyBinding("S+DELETE", InputHandler.DELETE);
+
+ // the following two were changing for 0122 for better mac/pc compatability
+ inputHandler.addKeyBinding(mod+"+BACK_SPACE", InputHandler.BACKSPACE_WORD);
+ inputHandler.addKeyBinding(mod+"+DELETE", InputHandler.DELETE_WORD);
+
+ // handled by listener, don't bother here
+ //inputHandler.addKeyBinding("ENTER", InputHandler.INSERT_BREAK);
+ //inputHandler.addKeyBinding("TAB", InputHandler.INSERT_TAB);
+
+ inputHandler.addKeyBinding("INSERT", InputHandler.OVERWRITE);
+ // disabling for 0122, not sure what this does
+ //inputHandler.addKeyBinding("C+\\", InputHandler.TOGGLE_RECT);
+
+ // for 0122, these have been changed for better compatability
+ // HOME and END now mean the beginning/end of the document
+ if (Base.isMacOS()) {
+ inputHandler.addKeyBinding("HOME", InputHandler.DOCUMENT_HOME);
+ inputHandler.addKeyBinding("END", InputHandler.DOCUMENT_END);
+ inputHandler.addKeyBinding("S+HOME", InputHandler.SELECT_DOC_HOME);
+ inputHandler.addKeyBinding("S+END", InputHandler.SELECT_DOC_END);
+ } else {
+ // for 0123 added the proper windows defaults
+ inputHandler.addKeyBinding("HOME", InputHandler.HOME);
+ inputHandler.addKeyBinding("END", InputHandler.END);
+ inputHandler.addKeyBinding("S+HOME", InputHandler.SELECT_HOME);
+ inputHandler.addKeyBinding("S+END", InputHandler.SELECT_END);
+ inputHandler.addKeyBinding("C+HOME", InputHandler.DOCUMENT_HOME);
+ inputHandler.addKeyBinding("C+END", InputHandler.DOCUMENT_END);
+ inputHandler.addKeyBinding("CS+HOME", InputHandler.SELECT_DOC_HOME);
+ inputHandler.addKeyBinding("CS+END", InputHandler.SELECT_DOC_END);
+ }
+
+ if (Base.isMacOS()) {
+ inputHandler.addKeyBinding("M+LEFT", InputHandler.HOME);
+ inputHandler.addKeyBinding("M+RIGHT", InputHandler.END);
+ inputHandler.addKeyBinding("MS+LEFT", InputHandler.SELECT_HOME); // 0122
+ inputHandler.addKeyBinding("MS+RIGHT", InputHandler.SELECT_END); // 0122
+ } else {
+ inputHandler.addKeyBinding("C+LEFT", InputHandler.HOME); // 0122
+ inputHandler.addKeyBinding("C+RIGHT", InputHandler.END); // 0122
+ inputHandler.addKeyBinding("CS+HOME", InputHandler.SELECT_HOME); // 0122
+ inputHandler.addKeyBinding("CS+END", InputHandler.SELECT_END); // 0122
+ }
+
+ inputHandler.addKeyBinding("PAGE_UP", InputHandler.PREV_PAGE);
+ inputHandler.addKeyBinding("PAGE_DOWN", InputHandler.NEXT_PAGE);
+ inputHandler.addKeyBinding("S+PAGE_UP", InputHandler.SELECT_PREV_PAGE);
+ inputHandler.addKeyBinding("S+PAGE_DOWN", InputHandler.SELECT_NEXT_PAGE);
+
+ inputHandler.addKeyBinding("LEFT", InputHandler.PREV_CHAR);
+ inputHandler.addKeyBinding("S+LEFT", InputHandler.SELECT_PREV_CHAR);
+ inputHandler.addKeyBinding(mod + "+LEFT", InputHandler.PREV_WORD);
+ inputHandler.addKeyBinding(mod + "S+LEFT", InputHandler.SELECT_PREV_WORD);
+ inputHandler.addKeyBinding("RIGHT", InputHandler.NEXT_CHAR);
+ inputHandler.addKeyBinding("S+RIGHT", InputHandler.SELECT_NEXT_CHAR);
+ inputHandler.addKeyBinding(mod + "+RIGHT", InputHandler.NEXT_WORD);
+ inputHandler.addKeyBinding(mod + "S+RIGHT", InputHandler.SELECT_NEXT_WORD);
+
+ inputHandler.addKeyBinding("UP", InputHandler.PREV_LINE);
+ inputHandler.addKeyBinding(mod + "+UP", InputHandler.PREV_LINE); // p5
+ inputHandler.addKeyBinding("S+UP", InputHandler.SELECT_PREV_LINE);
+ inputHandler.addKeyBinding("DOWN", InputHandler.NEXT_LINE);
+ inputHandler.addKeyBinding(mod + "+DOWN", InputHandler.NEXT_LINE); // p5
+ inputHandler.addKeyBinding("S+DOWN", InputHandler.SELECT_NEXT_LINE);
+
+ inputHandler.addKeyBinding("MS+UP", InputHandler.SELECT_DOC_HOME);
+ inputHandler.addKeyBinding("CS+UP", InputHandler.SELECT_DOC_HOME);
+ inputHandler.addKeyBinding("MS+DOWN", InputHandler.SELECT_DOC_END);
+ inputHandler.addKeyBinding("CS+DOWN", InputHandler.SELECT_DOC_END);
+
+ inputHandler.addKeyBinding(mod + "+ENTER", InputHandler.REPEAT);
+
+ document = new SyntaxDocument();
+ editable = true;
+ electricScroll = 3;
+
+ cols = 80;
+ rows = 15;
+
+
+ // moved from SyntaxUtilities
+ //DEFAULTS.styles = SyntaxUtilities.getDefaultSyntaxStyles();
+
+ styles = new SyntaxStyle[Token.ID_COUNT];
+
+ // comments
+ styles[Token.COMMENT1] = Theme.getStyle("comment1");
+ styles[Token.COMMENT2] = Theme.getStyle("comment2");
+
+ // abstract, final, private
+ styles[Token.KEYWORD1] = Theme.getStyle("keyword1");
+
+ // beginShape, point, line
+ styles[Token.KEYWORD2] = Theme.getStyle("keyword2");
+
+ // byte, char, short, color
+ styles[Token.KEYWORD3] = Theme.getStyle("keyword3");
+
+ // constants: null, true, this, RGB, TWO_PI
+ styles[Token.LITERAL1] = Theme.getStyle("literal1");
+
+ // p5 built in variables: mouseX, width, pixels
+ styles[Token.LITERAL2] = Theme.getStyle("literal2");
+
+ // ??
+ styles[Token.LABEL] = Theme.getStyle("label");
+
+ // + - = /
+ styles[Token.OPERATOR] = Theme.getStyle("operator");
+
+ // area that's not in use by the text (replaced with tildes)
+ styles[Token.INVALID] = Theme.getStyle("invalid");
+
+
+ // moved from TextAreaPainter
+
+ font = Preferences.getFont("editor.font");
+
+ fgcolor = Theme.getColor("editor.fgcolor");
+ bgcolor = Theme.getColor("editor.bgcolor");
+
+ caretVisible = true;
+ caretBlinks = Preferences.getBoolean("editor.caret.blink");
+ caretColor = Theme.getColor("editor.caret.color");
+
+ selectionColor = Theme.getColor("editor.selection.color");
+
+ lineHighlight =
+ Theme.getBoolean("editor.linehighlight");
+ lineHighlightColor =
+ Theme.getColor("editor.linehighlight.color");
+
+ bracketHighlight =
+ Theme.getBoolean("editor.brackethighlight");
+ bracketHighlightColor =
+ Theme.getColor("editor.brackethighlight.color");
+
+ eolMarkers = Theme.getBoolean("editor.eolmarkers");
+ eolMarkerColor = Theme.getColor("editor.eolmarkers.color");
+
+ paintInvalid = Theme.getBoolean("editor.invalid");
+ }
+}
diff --git a/app/src/processing/app/syntax/SyntaxDocument.java b/app/src/processing/app/syntax/SyntaxDocument.java
new file mode 100644
index 000000000..7b07a4269
--- /dev/null
+++ b/app/src/processing/app/syntax/SyntaxDocument.java
@@ -0,0 +1,166 @@
+/*
+ * SyntaxDocument.java - Document that can be tokenized
+ * Copyright (C) 1999 Slava Pestov
+ *
+ * You may use and modify this package for any purpose. Redistribution is
+ * permitted, in both source and binary form, provided that this notice
+ * remains intact in all source distributions of this package.
+ */
+
+package processing.app.syntax;
+
+import javax.swing.event.*;
+import javax.swing.text.*;
+import javax.swing.undo.UndoableEdit;
+
+/**
+ * A document implementation that can be tokenized by the syntax highlighting
+ * system.
+ *
+ * @author Slava Pestov
+ * @version $Id: SyntaxDocument.java 1268 2005-04-09 02:30:37Z benfry $
+ */
+public class SyntaxDocument extends PlainDocument
+{
+ /**
+ * Returns the token marker that is to be used to split lines
+ * of this document up into tokens. May return null if this
+ * document is not to be colorized.
+ */
+ public TokenMarker getTokenMarker()
+ {
+ return tokenMarker;
+ }
+
+ /**
+ * Sets the token marker that is to be used to split lines of
+ * this document up into tokens. May throw an exception if
+ * this is not supported for this type of document.
+ * @param tm The new token marker
+ */
+ public void setTokenMarker(TokenMarker tm)
+ {
+ tokenMarker = tm;
+ if(tm == null)
+ return;
+ tokenMarker.insertLines(0,getDefaultRootElement()
+ .getElementCount());
+ tokenizeLines();
+ }
+
+ /**
+ * Reparses the document, by passing all lines to the token
+ * marker. This should be called after the document is first
+ * loaded.
+ */
+ public void tokenizeLines()
+ {
+ tokenizeLines(0,getDefaultRootElement().getElementCount());
+ }
+
+ /**
+ * Reparses the document, by passing the specified lines to the
+ * token marker. This should be called after a large quantity of
+ * text is first inserted.
+ * @param start The first line to parse
+ * @param len The number of lines, after the first one to parse
+ */
+ public void tokenizeLines(int start, int len)
+ {
+ if(tokenMarker == null || !tokenMarker.supportsMultilineTokens())
+ return;
+
+ Segment lineSegment = new Segment();
+ Element map = getDefaultRootElement();
+
+ len += start;
+
+ try
+ {
+ for(int i = start; i < len; i++)
+ {
+ Element lineElement = map.getElement(i);
+ int lineStart = lineElement.getStartOffset();
+ getText(lineStart,lineElement.getEndOffset()
+ - lineStart - 1,lineSegment);
+ tokenMarker.markTokens(lineSegment,i);
+ }
+ }
+ catch(BadLocationException bl)
+ {
+ bl.printStackTrace();
+ }
+ }
+
+ /**
+ * Starts a compound edit that can be undone in one operation.
+ * Subclasses that implement undo should override this method;
+ * this class has no undo functionality so this method is
+ * empty.
+ */
+ public void beginCompoundEdit() {}
+
+ /**
+ * Ends a compound edit that can be undone in one operation.
+ * Subclasses that implement undo should override this method;
+ * this class has no undo functionality so this method is
+ * empty.
+ */
+ public void endCompoundEdit() {}
+
+ /**
+ * Adds an undoable edit to this document's undo list. The edit
+ * should be ignored if something is currently being undone.
+ * @param edit The undoable edit
+ *
+ * @since jEdit 2.2pre1
+ */
+ public void addUndoableEdit(UndoableEdit edit) {}
+
+ // protected members
+ protected TokenMarker tokenMarker;
+
+ /**
+ * We overwrite this method to update the token marker
+ * state immediately so that any event listeners get a
+ * consistent token marker.
+ */
+ protected void fireInsertUpdate(DocumentEvent evt)
+ {
+ if(tokenMarker != null)
+ {
+ DocumentEvent.ElementChange ch = evt.getChange(
+ getDefaultRootElement());
+ if(ch != null)
+ {
+ tokenMarker.insertLines(ch.getIndex() + 1,
+ ch.getChildrenAdded().length -
+ ch.getChildrenRemoved().length);
+ }
+ }
+
+ super.fireInsertUpdate(evt);
+ }
+
+ /**
+ * We overwrite this method to update the token marker
+ * state immediately so that any event listeners get a
+ * consistent token marker.
+ */
+ protected void fireRemoveUpdate(DocumentEvent evt)
+ {
+ if(tokenMarker != null)
+ {
+ DocumentEvent.ElementChange ch = evt.getChange(
+ getDefaultRootElement());
+ if(ch != null)
+ {
+ tokenMarker.deleteLines(ch.getIndex() + 1,
+ ch.getChildrenRemoved().length -
+ ch.getChildrenAdded().length);
+ }
+ }
+
+ super.fireRemoveUpdate(evt);
+ }
+}
diff --git a/app/src/processing/app/syntax/SyntaxStyle.java b/app/src/processing/app/syntax/SyntaxStyle.java
new file mode 100644
index 000000000..56323c3cc
--- /dev/null
+++ b/app/src/processing/app/syntax/SyntaxStyle.java
@@ -0,0 +1,138 @@
+/*
+ * SyntaxStyle.java - A simple text style class
+ * Copyright (C) 1999 Slava Pestov
+ *
+ * You may use and modify this package for any purpose. Redistribution is
+ * permitted, in both source and binary form, provided that this notice
+ * remains intact in all source distributions of this package.
+ */
+
+package processing.app.syntax;
+
+import java.awt.*;
+import javax.swing.JComponent;
+
+
+/**
+ * A simple text style class. It can specify the color, italic flag,
+ * and bold flag of a run of text.
+ * @author Slava Pestov
+ * @version $Id: SyntaxStyle.java 4824 2008-10-11 23:41:40Z fry $
+ */
+public class SyntaxStyle
+{
+ /**
+ * Creates a new SyntaxStyle.
+ * @param color The text color
+ * @param italic True if the text should be italics
+ * @param bold True if the text should be bold
+ */
+ public SyntaxStyle(Color color, boolean italic, boolean bold)
+ {
+ this.color = color;
+ this.italic = italic;
+ this.bold = bold;
+ }
+
+ /**
+ * Returns the color specified in this style.
+ */
+ public Color getColor()
+ {
+ return color;
+ }
+
+ /**
+ * Returns true if no font styles are enabled.
+ */
+ public boolean isPlain()
+ {
+ return !(bold || italic);
+ }
+
+ /**
+ * Returns true if italics is enabled for this style.
+ */
+ public boolean isItalic()
+ {
+ return italic;
+ }
+
+ /**
+ * Returns true if boldface is enabled for this style.
+ */
+ public boolean isBold()
+ {
+ return bold;
+ }
+
+ /**
+ * Returns the specified font, but with the style's bold and
+ * italic flags applied.
+ */
+ public Font getStyledFont(Font font)
+ {
+ if(font == null)
+ throw new NullPointerException("font param must not"
+ + " be null");
+ if(font.equals(lastFont))
+ return lastStyledFont;
+ lastFont = font;
+ lastStyledFont = new Font(font.getFamily(),
+ (bold ? Font.BOLD : 0)
+ | (italic ? Font.ITALIC : 0),
+ font.getSize());
+ return lastStyledFont;
+ }
+
+ /**
+ * Returns the font metrics for the styled font.
+ */
+ public FontMetrics getFontMetrics(Font font, JComponent comp)
+ {
+ if(font == null)
+ throw new NullPointerException("font param must not"
+ + " be null");
+ if(font.equals(lastFont) && fontMetrics != null)
+ return fontMetrics;
+ lastFont = font;
+ lastStyledFont = new Font(font.getFamily(),
+ (bold ? Font.BOLD : 0)
+ | (italic ? Font.ITALIC : 0),
+ font.getSize());
+ //fontMetrics = Toolkit.getDefaultToolkit().getFontMetrics(lastStyledFont);
+ fontMetrics = comp.getFontMetrics(lastStyledFont);
+ return fontMetrics;
+ }
+
+ /**
+ * Sets the foreground color and font of the specified graphics
+ * context to that specified in this style.
+ * @param gfx The graphics context
+ * @param font The font to add the styles to
+ */
+ public void setGraphicsFlags(Graphics gfx, Font font)
+ {
+ Font _font = getStyledFont(font);
+ gfx.setFont(_font);
+ gfx.setColor(color);
+ }
+
+ /**
+ * Returns a string representation of this object.
+ */
+ public String toString()
+ {
+ return getClass().getName() + "[color=" + color +
+ (italic ? ",italic" : "") +
+ (bold ? ",bold" : "") + "]";
+ }
+
+ // private members
+ private Color color;
+ private boolean italic;
+ private boolean bold;
+ private Font lastFont;
+ private Font lastStyledFont;
+ private FontMetrics fontMetrics;
+}
diff --git a/app/src/processing/app/syntax/SyntaxUtilities.java b/app/src/processing/app/syntax/SyntaxUtilities.java
new file mode 100644
index 000000000..5225d0b73
--- /dev/null
+++ b/app/src/processing/app/syntax/SyntaxUtilities.java
@@ -0,0 +1,163 @@
+/*
+ * SyntaxUtilities.java - Utility functions used by syntax colorizing
+ * Copyright (C) 1999 Slava Pestov
+ *
+ * You may use and modify this package for any purpose. Redistribution is
+ * permitted, in both source and binary form, provided that this notice
+ * remains intact in all source distributions of this package.
+ */
+
+package processing.app.syntax;
+
+import javax.swing.text.*;
+import java.awt.*;
+
+
+/**
+ * Class with several utility functions used by jEdit's syntax colorizing
+ * subsystem.
+ *
+ * @author Slava Pestov
+ * @version $Id: SyntaxUtilities.java 1268 2005-04-09 02:30:37Z benfry $
+ */
+public class SyntaxUtilities
+{
+ /**
+ * Checks if a subregion of a Segment is equal to a
+ * string.
+ * @param ignoreCase True if case should be ignored, false otherwise
+ * @param text The segment
+ * @param offset The offset into the segment
+ * @param match The string to match
+ */
+ public static boolean regionMatches(boolean ignoreCase, Segment text,
+ int offset, String match)
+ {
+ int length = offset + match.length();
+ char[] textArray = text.array;
+ if(length > text.offset + text.count)
+ return false;
+ for(int i = offset, j = 0; i < length; i++, j++)
+ {
+ char c1 = textArray[i];
+ char c2 = match.charAt(j);
+ if(ignoreCase)
+ {
+ c1 = Character.toUpperCase(c1);
+ c2 = Character.toUpperCase(c2);
+ }
+ if(c1 != c2)
+ return false;
+ }
+ return true;
+ }
+
+
+ /**
+ * Checks if a subregion of a Segment is equal to a
+ * character array.
+ * @param ignoreCase True if case should be ignored, false otherwise
+ * @param text The segment
+ * @param offset The offset into the segment
+ * @param match The character array to match
+ */
+ public static boolean regionMatches(boolean ignoreCase, Segment text,
+ int offset, char[] match)
+ {
+ int length = offset + match.length;
+ char[] textArray = text.array;
+ if(length > text.offset + text.count)
+ return false;
+ for(int i = offset, j = 0; i < length; i++, j++)
+ {
+ char c1 = textArray[i];
+ char c2 = match[j];
+ if(ignoreCase)
+ {
+ c1 = Character.toUpperCase(c1);
+ c2 = Character.toUpperCase(c2);
+ }
+ if(c1 != c2)
+ return false;
+ }
+ return true;
+ }
+
+
+ /**
+ * Returns the default style table. This can be passed to the
+ * setStyles() method of SyntaxDocument
+ * to use the default syntax styles.
+ */
+ public static SyntaxStyle[] getDefaultSyntaxStyles()
+ {
+ SyntaxStyle[] styles = new SyntaxStyle[Token.ID_COUNT];
+
+ styles[Token.COMMENT1] = new SyntaxStyle(Color.black,true,false);
+ styles[Token.COMMENT2] = new SyntaxStyle(new Color(0x990033),true,false);
+ styles[Token.KEYWORD1] = new SyntaxStyle(Color.black,false,true);
+ styles[Token.KEYWORD2] = new SyntaxStyle(Color.magenta,false,false);
+ styles[Token.KEYWORD3] = new SyntaxStyle(new Color(0x009600),false,false);
+ styles[Token.LITERAL1] = new SyntaxStyle(new Color(0x650099),false,false);
+ styles[Token.LITERAL2] = new SyntaxStyle(new Color(0x650099),false,true);
+ styles[Token.LABEL] = new SyntaxStyle(new Color(0x990033),false,true);
+ styles[Token.OPERATOR] = new SyntaxStyle(Color.black,false,true);
+ styles[Token.INVALID] = new SyntaxStyle(Color.red,false,true);
+
+ return styles;
+ }
+
+
+ /**
+ * Paints the specified line onto the graphics context. Note that this
+ * method munges the offset and count values of the segment.
+ * @param line The line segment
+ * @param tokens The token list for the line
+ * @param styles The syntax style list
+ * @param expander The tab expander used to determine tab stops. May
+ * be null
+ * @param gfx The graphics context
+ * @param x The x co-ordinate
+ * @param y The y co-ordinate
+ * @return The x co-ordinate, plus the width of the painted string
+ */
+ public static int paintSyntaxLine(Segment line, Token tokens,
+ SyntaxStyle[] styles,
+ TabExpander expander, Graphics gfx,
+ int x, int y)
+ {
+ Font defaultFont = gfx.getFont();
+ Color defaultColor = gfx.getColor();
+
+ int offset = 0;
+ for(;;)
+ {
+ byte id = tokens.id;
+ if(id == Token.END)
+ break;
+
+ int length = tokens.length;
+ if(id == Token.NULL)
+ {
+ if(!defaultColor.equals(gfx.getColor()))
+ gfx.setColor(defaultColor);
+ if(!defaultFont.equals(gfx.getFont()))
+ gfx.setFont(defaultFont);
+ }
+ else
+ styles[id].setGraphicsFlags(gfx,defaultFont);
+
+ line.count = length;
+ x = Utilities.drawTabbedText(line,x,y,gfx,expander,0);
+ line.offset += length;
+ offset += length;
+
+ tokens = tokens.next;
+ }
+
+ return x;
+ }
+
+ // private members
+ private SyntaxUtilities() {}
+}
diff --git a/app/src/processing/app/syntax/TextAreaDefaults.java b/app/src/processing/app/syntax/TextAreaDefaults.java
new file mode 100644
index 000000000..c2e878578
--- /dev/null
+++ b/app/src/processing/app/syntax/TextAreaDefaults.java
@@ -0,0 +1,90 @@
+/*
+ * TextAreaDefaults.java - Encapsulates default values for various settings
+ * Copyright (C) 1999 Slava Pestov
+ *
+ * You may use and modify this package for any purpose. Redistribution is
+ * permitted, in both source and binary form, provided that this notice
+ * remains intact in all source distributions of this package.
+ */
+
+package processing.app.syntax;
+
+import java.awt.*;
+//import javax.swing.JPopupMenu;
+
+/**
+ * Encapsulates default settings for a text area. This can be passed
+ * to the constructor once the necessary fields have been filled out.
+ * The advantage of doing this over calling lots of set() methods after
+ * creating the text area is that this method is faster.
+ */
+public class TextAreaDefaults
+{
+ private static TextAreaDefaults DEFAULTS;
+
+ public InputHandler inputHandler;
+ public SyntaxDocument document;
+ public boolean editable;
+
+ public boolean caretVisible;
+ public boolean caretBlinks;
+ public boolean blockCaret;
+ public int electricScroll;
+
+ public int cols;
+ public int rows;
+ public SyntaxStyle[] styles;
+ public Color caretColor;
+ public Color selectionColor;
+ public Color lineHighlightColor;
+ public boolean lineHighlight;
+ public Color bracketHighlightColor;
+ public boolean bracketHighlight;
+ public Color eolMarkerColor;
+ public boolean eolMarkers;
+ public boolean paintInvalid;
+
+
+ // moved from TextAreaPainter [fry]
+ public Font font;
+ public Color fgcolor;
+ public Color bgcolor;
+
+ //public JPopupMenu popup;
+
+
+ /**
+ * Returns a new TextAreaDefaults object with the default values filled
+ * in.
+ */
+ public static TextAreaDefaults getDefaults()
+ {
+ if (DEFAULTS == null) {
+ DEFAULTS = new TextAreaDefaults();
+
+ DEFAULTS.inputHandler = new DefaultInputHandler();
+ DEFAULTS.inputHandler.addDefaultKeyBindings();
+ DEFAULTS.document = new SyntaxDocument();
+ DEFAULTS.editable = true;
+
+ DEFAULTS.caretVisible = true;
+ DEFAULTS.caretBlinks = true;
+ DEFAULTS.electricScroll = 3;
+
+ DEFAULTS.cols = 80;
+ DEFAULTS.rows = 25;
+ DEFAULTS.styles = SyntaxUtilities.getDefaultSyntaxStyles();
+ DEFAULTS.caretColor = Color.red;
+ DEFAULTS.selectionColor = new Color(0xccccff);
+ DEFAULTS.lineHighlightColor = new Color(0xe0e0e0);
+ DEFAULTS.lineHighlight = true;
+ DEFAULTS.bracketHighlightColor = Color.black;
+ DEFAULTS.bracketHighlight = true;
+ DEFAULTS.eolMarkerColor = new Color(0x009999);
+ DEFAULTS.eolMarkers = true;
+ DEFAULTS.paintInvalid = true;
+ }
+
+ return DEFAULTS;
+ }
+}
diff --git a/app/src/processing/app/syntax/TextAreaPainter.java b/app/src/processing/app/syntax/TextAreaPainter.java
new file mode 100644
index 000000000..ef205b079
--- /dev/null
+++ b/app/src/processing/app/syntax/TextAreaPainter.java
@@ -0,0 +1,756 @@
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+/*
+ * TextAreaPainter.java - Paints the text area
+ * Copyright (C) 1999 Slava Pestov
+ *
+ * You may use and modify this package for any purpose. Redistribution is
+ * permitted, in both source and binary form, provided that this notice
+ * remains intact in all source distributions of this package.
+ */
+
+package processing.app.syntax;
+
+import processing.app.*;
+
+import javax.swing.ToolTipManager;
+import javax.swing.text.*;
+import javax.swing.JComponent;
+import java.awt.event.MouseEvent;
+import java.awt.*;
+import java.awt.print.*;
+
+/**
+ * The text area repaint manager. It performs double buffering and paints
+ * lines of text.
+ * @author Slava Pestov
+ */
+public class TextAreaPainter extends JComponent
+implements TabExpander, Printable
+{
+ /** True if inside printing, will handle disabling the highlight */
+ boolean printing;
+
+ /**
+ * Creates a new repaint manager. This should be not be called
+ * directly.
+ */
+ public TextAreaPainter(JEditTextArea textArea, TextAreaDefaults defaults)
+ {
+ this.textArea = textArea;
+
+ setAutoscrolls(true);
+ setDoubleBuffered(true);
+ setOpaque(true);
+
+ ToolTipManager.sharedInstance().registerComponent(this);
+
+ currentLine = new Segment();
+ currentLineIndex = -1;
+
+ setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
+
+ setFont(defaults.font);
+ setForeground(defaults.fgcolor);
+ setBackground(defaults.bgcolor);
+
+ blockCaret = defaults.blockCaret;
+ styles = defaults.styles;
+ cols = defaults.cols;
+ rows = defaults.rows;
+ caretColor = defaults.caretColor;
+ selectionColor = defaults.selectionColor;
+ lineHighlightColor = defaults.lineHighlightColor;
+ lineHighlight = defaults.lineHighlight;
+ bracketHighlightColor = defaults.bracketHighlightColor;
+ bracketHighlight = defaults.bracketHighlight;
+ paintInvalid = defaults.paintInvalid;
+ eolMarkerColor = defaults.eolMarkerColor;
+ eolMarkers = defaults.eolMarkers;
+ }
+
+ /**
+ * Returns if this component can be traversed by pressing the
+ * Tab key. This returns false.
+ */
+ public final boolean isManagingFocus()
+ {
+ return false;
+ }
+
+ /**
+ * Returns the syntax styles used to paint colorized text. Entry n
+ * will be used to paint tokens with id = n.
+ * @see processing.app.syntax.Token
+ */
+ public final SyntaxStyle[] getStyles()
+ {
+ return styles;
+ }
+
+ /**
+ * Sets the syntax styles used to paint colorized text. Entry n
+ * will be used to paint tokens with id = n.
+ * @param styles The syntax styles
+ * @see processing.app.syntax.Token
+ */
+ public final void setStyles(SyntaxStyle[] styles)
+ {
+ this.styles = styles;
+ repaint();
+ }
+
+ /**
+ * Returns the caret color.
+ */
+ public final Color getCaretColor()
+ {
+ return caretColor;
+ }
+
+ /**
+ * Sets the caret color.
+ * @param caretColor The caret color
+ */
+ public final void setCaretColor(Color caretColor)
+ {
+ this.caretColor = caretColor;
+ invalidateSelectedLines();
+ }
+
+ /**
+ * Returns the selection color.
+ */
+ public final Color getSelectionColor()
+ {
+ return selectionColor;
+ }
+
+ /**
+ * Sets the selection color.
+ * @param selectionColor The selection color
+ */
+ public final void setSelectionColor(Color selectionColor)
+ {
+ this.selectionColor = selectionColor;
+ invalidateSelectedLines();
+ }
+
+ /**
+ * Returns the line highlight color.
+ */
+ public final Color getLineHighlightColor()
+ {
+ return lineHighlightColor;
+ }
+
+ /**
+ * Sets the line highlight color.
+ * @param lineHighlightColor The line highlight color
+ */
+ public final void setLineHighlightColor(Color lineHighlightColor)
+ {
+ this.lineHighlightColor = lineHighlightColor;
+ invalidateSelectedLines();
+ }
+
+ /**
+ * Returns true if line highlight is enabled, false otherwise.
+ */
+ public final boolean isLineHighlightEnabled()
+ {
+ return lineHighlight;
+ }
+
+ /**
+ * Enables or disables current line highlighting.
+ * @param lineHighlight True if current line highlight
+ * should be enabled, false otherwise
+ */
+ public final void setLineHighlightEnabled(boolean lineHighlight)
+ {
+ this.lineHighlight = lineHighlight;
+ invalidateSelectedLines();
+ }
+
+ /**
+ * Returns the bracket highlight color.
+ */
+ public final Color getBracketHighlightColor()
+ {
+ return bracketHighlightColor;
+ }
+
+ /**
+ * Sets the bracket highlight color.
+ * @param bracketHighlightColor The bracket highlight color
+ */
+ public final void setBracketHighlightColor(Color bracketHighlightColor)
+ {
+ this.bracketHighlightColor = bracketHighlightColor;
+ invalidateLine(textArea.getBracketLine());
+ }
+
+ /**
+ * Returns true if bracket highlighting is enabled, false otherwise.
+ * When bracket highlighting is enabled, the bracket matching the
+ * one before the caret (if any) is highlighted.
+ */
+ public final boolean isBracketHighlightEnabled()
+ {
+ return bracketHighlight;
+ }
+
+ /**
+ * Enables or disables bracket highlighting.
+ * When bracket highlighting is enabled, the bracket matching the
+ * one before the caret (if any) is highlighted.
+ * @param bracketHighlight True if bracket highlighting should be
+ * enabled, false otherwise
+ */
+ public final void setBracketHighlightEnabled(boolean bracketHighlight)
+ {
+ this.bracketHighlight = bracketHighlight;
+ invalidateLine(textArea.getBracketLine());
+ }
+
+ /**
+ * Returns true if the caret should be drawn as a block, false otherwise.
+ */
+ public final boolean isBlockCaretEnabled()
+ {
+ return blockCaret;
+ }
+
+ /**
+ * Sets if the caret should be drawn as a block, false otherwise.
+ * @param blockCaret True if the caret should be drawn as a block,
+ * false otherwise.
+ */
+ public final void setBlockCaretEnabled(boolean blockCaret)
+ {
+ this.blockCaret = blockCaret;
+ invalidateSelectedLines();
+ }
+
+ /**
+ * Returns the EOL marker color.
+ */
+ public final Color getEOLMarkerColor()
+ {
+ return eolMarkerColor;
+ }
+
+ /**
+ * Sets the EOL marker color.
+ * @param eolMarkerColor The EOL marker color
+ */
+ public final void setEOLMarkerColor(Color eolMarkerColor)
+ {
+ this.eolMarkerColor = eolMarkerColor;
+ repaint();
+ }
+
+ /**
+ * Returns true if EOL markers are drawn, false otherwise.
+ */
+ public final boolean getEOLMarkersPainted()
+ {
+ return eolMarkers;
+ }
+
+ /**
+ * Sets if EOL markers are to be drawn.
+ * @param eolMarkers True if EOL markers should be drawn, false otherwise
+ */
+ public final void setEOLMarkersPainted(boolean eolMarkers)
+ {
+ this.eolMarkers = eolMarkers;
+ repaint();
+ }
+
+ /**
+ * Returns true if invalid lines are painted as red tildes (~),
+ * false otherwise.
+ */
+ public boolean getInvalidLinesPainted()
+ {
+ return paintInvalid;
+ }
+
+ /**
+ * Sets if invalid lines are to be painted as red tildes.
+ * @param paintInvalid True if invalid lines should be drawn, false otherwise
+ */
+ public void setInvalidLinesPainted(boolean paintInvalid)
+ {
+ this.paintInvalid = paintInvalid;
+ }
+
+ /**
+ * Adds a custom highlight painter.
+ * @param highlight The highlight
+ */
+ public void addCustomHighlight(Highlight highlight)
+ {
+ highlight.init(textArea,highlights);
+ highlights = highlight;
+ }
+
+ /**
+ * Highlight interface.
+ */
+ public interface Highlight
+ {
+ /**
+ * Called after the highlight painter has been added.
+ * @param textArea The text area
+ * @param next The painter this one should delegate to
+ */
+ void init(JEditTextArea textArea, Highlight next);
+
+ /**
+ * This should paint the highlight and delgate to the
+ * next highlight painter.
+ * @param gfx The graphics context
+ * @param line The line number
+ * @param y The y co-ordinate of the line
+ */
+ void paintHighlight(Graphics gfx, int line, int y);
+
+ /**
+ * Returns the tool tip to display at the specified
+ * location. If this highlighter doesn't know what to
+ * display, it should delegate to the next highlight
+ * painter.
+ * @param evt The mouse event
+ */
+ String getToolTipText(MouseEvent evt);
+ }
+
+ /**
+ * Returns the tool tip to display at the specified location.
+ * @param evt The mouse event
+ */
+ public String getToolTipText(MouseEvent evt)
+ {
+ if(highlights != null)
+ return highlights.getToolTipText(evt);
+ else
+ return null;
+ }
+
+ /**
+ * Returns the font metrics used by this component.
+ */
+ public FontMetrics getFontMetrics()
+ {
+ return fm;
+ }
+
+ /**
+ * Sets the font for this component. This is overridden to update the
+ * cached font metrics and to recalculate which lines are visible.
+ * @param font The font
+ */
+ public void setFont(Font font)
+ {
+ super.setFont(font);
+ fm = super.getFontMetrics(font);
+ textArea.recalculateVisibleLines();
+ }
+
+ /**
+ * Repaints the text.
+ * @param gfx The graphics context
+ */
+ public void paint(Graphics gfx)
+ {
+ if (Base.isMacOS()) {
+ Graphics2D g2 = (Graphics2D) gfx;
+ g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
+ RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
+ }
+
+ tabSize = fm.charWidth(' ') * ((Integer)textArea.getDocument().getProperty(PlainDocument.tabSizeAttribute)).intValue();
+
+ Rectangle clipRect = gfx.getClipBounds();
+
+ gfx.setColor(getBackground());
+ gfx.fillRect(clipRect.x,clipRect.y,clipRect.width,clipRect.height);
+
+ // We don't use yToLine() here because that method doesn't
+ // return lines past the end of the document
+ int height = fm.getHeight();
+ int firstLine = textArea.getFirstLine();
+ int firstInvalid = firstLine + clipRect.y / height;
+ // Because the clipRect's height is usually an even multiple
+ // of the font height, we subtract 1 from it, otherwise one
+ // too many lines will always be painted.
+ int lastInvalid = firstLine + (clipRect.y + clipRect.height - 1) / height;
+
+ try {
+ TokenMarker tokenMarker = textArea.getDocument().getTokenMarker();
+ int x = textArea.getHorizontalOffset();
+
+ for (int line = firstInvalid; line <= lastInvalid; line++) {
+ paintLine(gfx,tokenMarker,line,x);
+ }
+
+ if (tokenMarker != null && tokenMarker.isNextLineRequested()) {
+ int h = clipRect.y + clipRect.height;
+ repaint(0,h,getWidth(),getHeight() - h);
+ }
+ } catch (Exception e) {
+ System.err.println("Error repainting line"
+ + " range {" + firstInvalid + ","
+ + lastInvalid + "}:");
+ e.printStackTrace();
+ }
+ }
+
+
+ public int print(Graphics g, PageFormat pageFormat, int pageIndex) {
+ int lineHeight = fm.getHeight();
+ int linesPerPage = (int) (pageFormat.getImageableHeight() / lineHeight);
+ int lineCount = textArea.getLineCount();
+ int lastPage = lineCount / linesPerPage;
+
+ if (pageIndex > lastPage) {
+ return NO_SUCH_PAGE;
+
+ } else {
+ Graphics2D g2d = (Graphics2D)g;
+ TokenMarker tokenMarker = textArea.getDocument().getTokenMarker();
+ int firstLine = pageIndex*linesPerPage;
+ g2d.translate(Math.max(54, pageFormat.getImageableX()),
+ pageFormat.getImageableY() - firstLine*lineHeight);
+ printing = true;
+ for (int line = firstLine; line < firstLine + linesPerPage; line++) {
+ paintLine(g2d, tokenMarker, line, 0);
+ }
+ printing = false;
+ return PAGE_EXISTS;
+ }
+ }
+
+
+ /**
+ * Marks a line as needing a repaint.
+ * @param line The line to invalidate
+ */
+ public final void invalidateLine(int line)
+ {
+ repaint(0,textArea.lineToY(line) + fm.getMaxDescent() + fm.getLeading(),
+ getWidth(),fm.getHeight());
+ }
+
+ /**
+ * Marks a range of lines as needing a repaint.
+ * @param firstLine The first line to invalidate
+ * @param lastLine The last line to invalidate
+ */
+ public final void invalidateLineRange(int firstLine, int lastLine)
+ {
+ repaint(0,textArea.lineToY(firstLine) +
+ fm.getMaxDescent() + fm.getLeading(),
+ getWidth(),(lastLine - firstLine + 1) * fm.getHeight());
+ }
+
+ /**
+ * Repaints the lines containing the selection.
+ */
+ public final void invalidateSelectedLines()
+ {
+ invalidateLineRange(textArea.getSelectionStartLine(),
+ textArea.getSelectionStopLine());
+ }
+
+ /**
+ * Implementation of TabExpander interface. Returns next tab stop after
+ * a specified point.
+ * @param x The x co-ordinate
+ * @param tabOffset Ignored
+ * @return The next tab stop after x
+ */
+ public float nextTabStop(float x, int tabOffset)
+ {
+ int offset = textArea.getHorizontalOffset();
+ int ntabs = ((int)x - offset) / tabSize;
+ return (ntabs + 1) * tabSize + offset;
+ }
+
+ /**
+ * Returns the painter's preferred size.
+ */
+ public Dimension getPreferredSize()
+ {
+ Dimension dim = new Dimension();
+ dim.width = fm.charWidth('w') * cols;
+ dim.height = fm.getHeight() * rows;
+ return dim;
+ }
+
+
+ /**
+ * Returns the painter's minimum size.
+ */
+ public Dimension getMinimumSize()
+ {
+ return getPreferredSize();
+ }
+
+ // package-private members
+ int currentLineIndex;
+ Token currentLineTokens;
+ Segment currentLine;
+
+ /**
+ * Accessor used by tools that want to hook in and grab the formatting.
+ */
+ public int getCurrentLineIndex() {
+ return currentLineIndex;
+ }
+
+ /**
+ * Accessor used by tools that want to hook in and grab the formatting.
+ */
+ public void setCurrentLineIndex(int what) {
+ currentLineIndex = what;
+ }
+
+ /**
+ * Accessor used by tools that want to hook in and grab the formatting.
+ */
+ public Token getCurrentLineTokens() {
+ return currentLineTokens;
+ }
+
+ /**
+ * Accessor used by tools that want to hook in and grab the formatting.
+ */
+ public void setCurrentLineTokens(Token tokens) {
+ currentLineTokens = tokens;
+ }
+
+ /**
+ * Accessor used by tools that want to hook in and grab the formatting.
+ */
+ public Segment getCurrentLine() {
+ return currentLine;
+ }
+
+
+ // protected members
+ protected JEditTextArea textArea;
+
+ protected SyntaxStyle[] styles;
+ protected Color caretColor;
+ protected Color selectionColor;
+ protected Color lineHighlightColor;
+ protected Color bracketHighlightColor;
+ protected Color eolMarkerColor;
+
+ protected boolean blockCaret;
+ protected boolean lineHighlight;
+ protected boolean bracketHighlight;
+ protected boolean paintInvalid;
+ protected boolean eolMarkers;
+ protected int cols;
+ protected int rows;
+
+ protected int tabSize;
+ protected FontMetrics fm;
+
+ protected Highlight highlights;
+
+ protected void paintLine(Graphics gfx, TokenMarker tokenMarker,
+ int line, int x)
+ {
+ Font defaultFont = getFont();
+ Color defaultColor = getForeground();
+
+ currentLineIndex = line;
+ int y = textArea.lineToY(line);
+
+ if (line < 0 || line >= textArea.getLineCount()) {
+ if (paintInvalid) {
+ paintHighlight(gfx,line,y);
+ styles[Token.INVALID].setGraphicsFlags(gfx,defaultFont);
+ gfx.drawString("~",0,y + fm.getHeight());
+ }
+ } else if(tokenMarker == null) {
+ paintPlainLine(gfx,line,defaultFont,defaultColor,x,y);
+ } else {
+ paintSyntaxLine(gfx,tokenMarker,line,defaultFont,
+ defaultColor,x,y);
+ }
+ }
+
+ protected void paintPlainLine(Graphics gfx, int line, Font defaultFont,
+ Color defaultColor, int x, int y)
+ {
+ paintHighlight(gfx,line,y);
+ textArea.getLineText(line,currentLine);
+
+ gfx.setFont(defaultFont);
+ gfx.setColor(defaultColor);
+
+ y += fm.getHeight();
+ x = Utilities.drawTabbedText(currentLine,x,y,gfx,this,0);
+
+ if (eolMarkers) {
+ gfx.setColor(eolMarkerColor);
+ gfx.drawString(".",x,y);
+ }
+ }
+
+ protected void paintSyntaxLine(Graphics gfx, TokenMarker tokenMarker,
+ int line, Font defaultFont,
+ Color defaultColor, int x, int y)
+ {
+ textArea.getLineText(currentLineIndex,currentLine);
+ currentLineTokens = tokenMarker.markTokens(currentLine,
+ currentLineIndex);
+
+ paintHighlight(gfx,line,y);
+
+ gfx.setFont(defaultFont);
+ gfx.setColor(defaultColor);
+ y += fm.getHeight();
+ x = SyntaxUtilities.paintSyntaxLine(currentLine,
+ currentLineTokens,
+ styles, this, gfx, x, y);
+
+ if (eolMarkers) {
+ gfx.setColor(eolMarkerColor);
+ gfx.drawString(".",x,y);
+ }
+ }
+
+ protected void paintHighlight(Graphics gfx, int line, int y)
+ {
+ if (!printing) {
+ if (line >= textArea.getSelectionStartLine()
+ && line <= textArea.getSelectionStopLine())
+ paintLineHighlight(gfx,line,y);
+
+ if (highlights != null)
+ highlights.paintHighlight(gfx,line,y);
+
+ if (bracketHighlight && line == textArea.getBracketLine())
+ paintBracketHighlight(gfx,line,y);
+
+ if (line == textArea.getCaretLine())
+ paintCaret(gfx,line,y);
+ }
+ }
+
+ protected void paintLineHighlight(Graphics gfx, int line, int y)
+ {
+ int height = fm.getHeight();
+ y += fm.getLeading() + fm.getMaxDescent();
+
+ int selectionStart = textArea.getSelectionStart();
+ int selectionEnd = textArea.getSelectionStop();
+
+ if (selectionStart == selectionEnd) {
+ if (lineHighlight) {
+ gfx.setColor(lineHighlightColor);
+ gfx.fillRect(0,y,getWidth(),height);
+ }
+ } else {
+ gfx.setColor(selectionColor);
+
+ int selectionStartLine = textArea.getSelectionStartLine();
+ int selectionEndLine = textArea.getSelectionStopLine();
+ int lineStart = textArea.getLineStartOffset(line);
+
+ int x1, x2;
+ if (textArea.isSelectionRectangular()) {
+ int lineLen = textArea.getLineLength(line);
+ x1 = textArea._offsetToX(line,Math.min(lineLen, selectionStart - textArea.getLineStartOffset(selectionStartLine)));
+ x2 = textArea._offsetToX(line,Math.min(lineLen, selectionEnd - textArea.getLineStartOffset(selectionEndLine)));
+ if (x1 == x2)
+ x2++;
+ } else if(selectionStartLine == selectionEndLine) {
+ x1 = textArea._offsetToX(line, selectionStart - lineStart);
+ x2 = textArea._offsetToX(line, selectionEnd - lineStart);
+ } else if(line == selectionStartLine) {
+ x1 = textArea._offsetToX(line, selectionStart - lineStart);
+ x2 = getWidth();
+ } else if(line == selectionEndLine) {
+ //x1 = 0;
+ // hack from stendahl to avoid doing weird side selection thing
+ x1 = textArea._offsetToX(line, 0);
+ // attempt at getting the gutter too, but doesn't seem to work
+ //x1 = textArea._offsetToX(line, -textArea.getHorizontalOffset());
+ x2 = textArea._offsetToX(line, selectionEnd - lineStart);
+ } else {
+ //x1 = 0;
+ // hack from stendahl to avoid doing weird side selection thing
+ x1 = textArea._offsetToX(line, 0);
+ // attempt at getting the gutter too, but doesn't seem to work
+ //x1 = textArea._offsetToX(line, -textArea.getHorizontalOffset());
+ x2 = getWidth();
+ }
+
+ // "inlined" min/max()
+ gfx.fillRect(x1 > x2 ? x2 : x1,y,x1 > x2 ?
+ (x1 - x2) : (x2 - x1),height);
+ }
+
+ }
+
+ protected void paintBracketHighlight(Graphics gfx, int line, int y)
+ {
+ int position = textArea.getBracketPosition();
+ if(position == -1)
+ return;
+ y += fm.getLeading() + fm.getMaxDescent();
+ int x = textArea._offsetToX(line,position);
+ gfx.setColor(bracketHighlightColor);
+ // Hack!!! Since there is no fast way to get the character
+ // from the bracket matching routine, we use ( since all
+ // brackets probably have the same width anyway
+ gfx.drawRect(x,y,fm.charWidth('(') - 1,
+ fm.getHeight() - 1);
+ }
+
+ protected void paintCaret(Graphics gfx, int line, int y)
+ {
+ //System.out.println("painting caret " + line + " " + y);
+ if (textArea.isCaretVisible()) {
+ //System.out.println("caret is visible");
+ int offset =
+ textArea.getCaretPosition() - textArea.getLineStartOffset(line);
+ int caretX = textArea._offsetToX(line, offset);
+ int caretWidth = ((blockCaret ||
+ textArea.isOverwriteEnabled()) ?
+ fm.charWidth('w') : 1);
+ y += fm.getLeading() + fm.getMaxDescent();
+ int height = fm.getHeight();
+
+ //System.out.println("caretX, width = " + caretX + " " + caretWidth);
+
+ gfx.setColor(caretColor);
+
+ if (textArea.isOverwriteEnabled()) {
+ gfx.fillRect(caretX,y + height - 1, caretWidth,1);
+
+ } else {
+ // some machines don't like the drawRect for the single
+ // pixel caret.. this caused a lot of hell because on that
+ // minority of machines, the caret wouldn't show up past
+ // the first column. the fix is to use drawLine() in
+ // those cases, as a workaround.
+ if (caretWidth == 1) {
+ gfx.drawLine(caretX, y, caretX, y + height - 1);
+ } else {
+ gfx.drawRect(caretX, y, caretWidth - 1, height - 1);
+ }
+ //gfx.drawRect(caretX, y, caretWidth, height - 1);
+ }
+ }
+ }
+}
diff --git a/app/src/processing/app/syntax/TextUtilities.java b/app/src/processing/app/syntax/TextUtilities.java
new file mode 100644
index 000000000..d31f8f3b7
--- /dev/null
+++ b/app/src/processing/app/syntax/TextUtilities.java
@@ -0,0 +1,184 @@
+/*
+ * TextUtilities.java - Utility functions used by the text area classes
+ * Copyright (C) 1999 Slava Pestov
+ *
+ * You may use and modify this package for any purpose. Redistribution is
+ * permitted, in both source and binary form, provided that this notice
+ * remains intact in all source distributions of this package.
+ */
+
+package processing.app.syntax;
+
+import javax.swing.text.*;
+
+/**
+ * Class with several utility functions used by the text area component.
+ * @author Slava Pestov
+ * @version $Id: TextUtilities.java 1268 2005-04-09 02:30:37Z benfry $
+ */
+public class TextUtilities
+{
+ /**
+ * Returns the offset of the bracket matching the one at the
+ * specified offset of the document, or -1 if the bracket is
+ * unmatched (or if the character is not a bracket).
+ * @param doc The document
+ * @param offset The offset
+ * @exception BadLocationException If an out-of-bounds access
+ * was attempted on the document text
+ */
+ public static int findMatchingBracket(Document doc, int offset)
+ throws BadLocationException
+ {
+ if(doc.getLength() == 0)
+ return -1;
+ char c = doc.getText(offset,1).charAt(0);
+ char cprime; // c` - corresponding character
+ boolean direction; // true = back, false = forward
+
+ switch(c)
+ {
+ case '(': cprime = ')'; direction = false; break;
+ case ')': cprime = '('; direction = true; break;
+ case '[': cprime = ']'; direction = false; break;
+ case ']': cprime = '['; direction = true; break;
+ case '{': cprime = '}'; direction = false; break;
+ case '}': cprime = '{'; direction = true; break;
+ default: return -1;
+ }
+
+ int count;
+
+ // How to merge these two cases is left as an exercise
+ // for the reader.
+
+ // Go back or forward
+ if(direction)
+ {
+ // Count is 1 initially because we have already
+ // `found' one closing bracket
+ count = 1;
+
+ // Get text[0,offset-1];
+ String text = doc.getText(0,offset);
+
+ // Scan backwards
+ for(int i = offset - 1; i >= 0; i--)
+ {
+ // If text[i] == c, we have found another
+ // closing bracket, therefore we will need
+ // two opening brackets to complete the
+ // match.
+ char x = text.charAt(i);
+ if(x == c)
+ count++;
+
+ // If text[i] == cprime, we have found a
+ // opening bracket, so we return i if
+ // --count == 0
+ else if(x == cprime)
+ {
+ if(--count == 0)
+ return i;
+ }
+ }
+ }
+ else
+ {
+ // Count is 1 initially because we have already
+ // `found' one opening bracket
+ count = 1;
+
+ // So we don't have to + 1 in every loop
+ offset++;
+
+ // Number of characters to check
+ int len = doc.getLength() - offset;
+
+ // Get text[offset+1,len];
+ String text = doc.getText(offset,len);
+
+ // Scan forwards
+ for(int i = 0; i < len; i++)
+ {
+ // If text[i] == c, we have found another
+ // opening bracket, therefore we will need
+ // two closing brackets to complete the
+ // match.
+ char x = text.charAt(i);
+
+ if(x == c)
+ count++;
+
+ // If text[i] == cprime, we have found an
+ // closing bracket, so we return i if
+ // --count == 0
+ else if(x == cprime)
+ {
+ if(--count == 0)
+ return i + offset;
+ }
+ }
+ }
+
+ // Nothing found
+ return -1;
+ }
+
+ /**
+ * Locates the start of the word at the specified position.
+ * @param line The text
+ * @param pos The position
+ */
+ public static int findWordStart(String line, int pos, String noWordSep)
+ {
+ char ch = line.charAt(pos - 1);
+
+ if(noWordSep == null)
+ noWordSep = "";
+ boolean selectNoLetter = (!Character.isLetterOrDigit(ch)
+ && noWordSep.indexOf(ch) == -1);
+
+ int wordStart = 0;
+ for(int i = pos - 1; i >= 0; i--)
+ {
+ ch = line.charAt(i);
+ if(selectNoLetter ^ (!Character.isLetterOrDigit(ch) &&
+ noWordSep.indexOf(ch) == -1))
+ {
+ wordStart = i + 1;
+ break;
+ }
+ }
+
+ return wordStart;
+ }
+
+ /**
+ * Locates the end of the word at the specified position.
+ * @param line The text
+ * @param pos The position
+ */
+ public static int findWordEnd(String line, int pos, String noWordSep)
+ {
+ char ch = line.charAt(pos);
+
+ if(noWordSep == null)
+ noWordSep = "";
+ boolean selectNoLetter = (!Character.isLetterOrDigit(ch)
+ && noWordSep.indexOf(ch) == -1);
+
+ int wordEnd = line.length();
+ for(int i = pos; i < line.length(); i++)
+ {
+ ch = line.charAt(i);
+ if(selectNoLetter ^ (!Character.isLetterOrDigit(ch) &&
+ noWordSep.indexOf(ch) == -1))
+ {
+ wordEnd = i;
+ break;
+ }
+ }
+ return wordEnd;
+ }
+}
diff --git a/app/src/processing/app/syntax/Token.java b/app/src/processing/app/syntax/Token.java
new file mode 100644
index 000000000..a0f73bebf
--- /dev/null
+++ b/app/src/processing/app/syntax/Token.java
@@ -0,0 +1,149 @@
+/*
+ * Token.java - Generic token
+ * Copyright (C) 1998, 1999 Slava Pestov
+ *
+ * You may use and modify this package for any purpose. Redistribution is
+ * permitted, in both source and binary form, provided that this notice
+ * remains intact in all source distributions of this package.
+ */
+
+package processing.app.syntax;
+
+/**
+ * A linked list of tokens. Each token has three fields - a token
+ * identifier, which is a byte value that can be looked up in the
+ * array returned by SyntaxDocument.getColors()
+ * to get a color value, a length value which is the length of the
+ * token in the text, and a pointer to the next token in the list.
+ *
+ * @author Slava Pestov
+ * @version $Id: Token.java 1268 2005-04-09 02:30:37Z benfry $
+ */
+public class Token
+{
+ /**
+ * Normal text token id. This should be used to mark
+ * normal text.
+ */
+ public static final byte NULL = 0;
+
+ /**
+ * Comment 1 token id. This can be used to mark a comment.
+ */
+ public static final byte COMMENT1 = 1;
+
+ /**
+ * Comment 2 token id. This can be used to mark a comment.
+ */
+ public static final byte COMMENT2 = 2;
+
+
+ /**
+ * Literal 1 token id. This can be used to mark a string
+ * literal (eg, C mode uses this to mark "..." literals)
+ */
+ public static final byte LITERAL1 = 3;
+
+ /**
+ * Literal 2 token id. This can be used to mark an object
+ * literal (eg, Java mode uses this to mark true, false, etc)
+ */
+ public static final byte LITERAL2 = 4;
+
+ /**
+ * Label token id. This can be used to mark labels
+ * (eg, C mode uses this to mark ...: sequences)
+ */
+ public static final byte LABEL = 5;
+
+ /**
+ * Keyword 1 token id. This can be used to mark a
+ * keyword. This should be used for general language
+ * constructs.
+ */
+ public static final byte KEYWORD1 = 6;
+
+ /**
+ * Keyword 2 token id. This can be used to mark a
+ * keyword. This should be used for preprocessor
+ * commands, or variables.
+ */
+ public static final byte KEYWORD2 = 7;
+
+ /**
+ * Keyword 3 token id. This can be used to mark a
+ * keyword. This should be used for data types.
+ */
+ public static final byte KEYWORD3 = 8;
+
+ /**
+ * Operator token id. This can be used to mark an
+ * operator. (eg, SQL mode marks +, -, etc with this
+ * token type)
+ */
+ public static final byte OPERATOR = 9;
+
+ /**
+ * Invalid token id. This can be used to mark invalid
+ * or incomplete tokens, so the user can easily spot
+ * syntax errors.
+ */
+ public static final byte INVALID = 10;
+
+ /**
+ * The total number of defined token ids.
+ */
+ public static final byte ID_COUNT = 11;
+
+ /**
+ * The first id that can be used for internal state
+ * in a token marker.
+ */
+ public static final byte INTERNAL_FIRST = 100;
+
+ /**
+ * The last id that can be used for internal state
+ * in a token marker.
+ */
+ public static final byte INTERNAL_LAST = 126;
+
+ /**
+ * The token type, that along with a length of 0
+ * marks the end of the token list.
+ */
+ public static final byte END = 127;
+
+ /**
+ * The length of this token.
+ */
+ public int length;
+
+ /**
+ * The id of this token.
+ */
+ public byte id;
+
+ /**
+ * The next token in the linked list.
+ */
+ public Token next;
+
+ /**
+ * Creates a new token.
+ * @param length The length of the token
+ * @param id The id of the token
+ */
+ public Token(int length, byte id)
+ {
+ this.length = length;
+ this.id = id;
+ }
+
+ /**
+ * Returns a string representation of this token.
+ */
+ public String toString()
+ {
+ return "[id=" + id + ",length=" + length + "]";
+ }
+}
diff --git a/app/src/processing/app/syntax/TokenMarker.java b/app/src/processing/app/syntax/TokenMarker.java
new file mode 100644
index 000000000..9244556d3
--- /dev/null
+++ b/app/src/processing/app/syntax/TokenMarker.java
@@ -0,0 +1,341 @@
+/*
+ * TokenMarker.java - Generic token marker
+ * Copyright (C) 1998, 1999 Slava Pestov
+ *
+ * You may use and modify this package for any purpose. Redistribution is
+ * permitted, in both source and binary form, provided that this notice
+ * remains intact in all source distributions of this package.
+ */
+
+package processing.app.syntax;
+
+import javax.swing.text.Segment;
+
+/**
+ * A token marker that splits lines of text into tokens. Each token carries
+ * a length field and an indentification tag that can be mapped to a color
+ * for painting that token.
+ *
+ * For performance reasons, the linked list of tokens is reused after each
+ * line is tokenized. Therefore, the return value of markTokens
+ * should only be used for immediate painting. Notably, it cannot be
+ * cached.
+ *
+ * @author Slava Pestov
+ */
+public abstract class TokenMarker
+{
+ /**
+ * A wrapper for the lower-level markTokensImpl method
+ * that is called to split a line up into tokens.
+ * @param line The line
+ * @param lineIndex The line number
+ */
+ public Token markTokens(Segment line, int lineIndex)
+ {
+ if(lineIndex >= length)
+ {
+ throw new IllegalArgumentException("Tokenizing invalid line: "
+ + lineIndex);
+ }
+
+ lastToken = null;
+
+ LineInfo info = lineInfo[lineIndex];
+ LineInfo prev;
+ if(lineIndex == 0)
+ prev = null;
+ else
+ prev = lineInfo[lineIndex - 1];
+
+ byte oldToken = info.token;
+ byte token = markTokensImpl(prev == null ?
+ Token.NULL : prev.token,line,lineIndex);
+
+ info.token = token;
+
+ /*
+ * This is a foul hack. It stops nextLineRequested
+ * from being cleared if the same line is marked twice.
+ *
+ * Why is this necessary? It's all JEditTextArea's fault.
+ * When something is inserted into the text, firing a
+ * document event, the insertUpdate() method shifts the
+ * caret (if necessary) by the amount inserted.
+ *
+ * All caret movement is handled by the select() method,
+ * which eventually pipes the new position to scrollTo()
+ * and calls repaint().
+ *
+ * Note that at this point in time, the new line hasn't
+ * yet been painted; the caret is moved first.
+ *
+ * scrollTo() calls offsetToX(), which tokenizes the line
+ * unless it is being called on the last line painted
+ * (in which case it uses the text area's painter cached
+ * token list). What scrollTo() does next is irrelevant.
+ *
+ * After scrollTo() has done it's job, repaint() is
+ * called, and eventually we end up in paintLine(), whose
+ * job is to paint the changed line. It, too, calls
+ * markTokens().
+ *
+ * The problem was that if the line started a multiline
+ * token, the first markTokens() (done in offsetToX())
+ * would set nextLineRequested (because the line end
+ * token had changed) but the second would clear it
+ * (because the line was the same that time) and therefore
+ * paintLine() would never know that it needed to repaint
+ * subsequent lines.
+ *
+ * This bug took me ages to track down, that's why I wrote
+ * all the relevant info down so that others wouldn't
+ * duplicate it.
+ */
+ if(!(lastLine == lineIndex && nextLineRequested))
+ nextLineRequested = (oldToken != token);
+
+ lastLine = lineIndex;
+
+ addToken(0,Token.END);
+
+ return firstToken;
+ }
+
+ /**
+ * An abstract method that splits a line up into tokens. It
+ * should parse the line, and call addToken() to
+ * add syntax tokens to the token list. Then, it should return
+ * the initial token type for the next line.
+ *
+ * For example if the current line contains the start of a
+ * multiline comment that doesn't end on that line, this method
+ * should return the comment token type so that it continues on
+ * the next line.
+ *
+ * @param token The initial token type for this line
+ * @param line The line to be tokenized
+ * @param lineIndex The index of the line in the document,
+ * starting at 0
+ * @return The initial token type for the next line
+ */
+ protected abstract byte markTokensImpl(byte token, Segment line,
+ int lineIndex);
+
+ /**
+ * Returns if the token marker supports tokens that span multiple
+ * lines. If this is true, the object using this token marker is
+ * required to pass all lines in the document to the
+ * markTokens() method (in turn).
+ *
+ * The default implementation returns true; it should be overridden
+ * to return false on simpler token markers for increased speed.
+ */
+ public boolean supportsMultilineTokens()
+ {
+ return true;
+ }
+
+ /**
+ * Informs the token marker that lines have been inserted into
+ * the document. This inserts a gap in the lineInfo
+ * array.
+ * @param index The first line number
+ * @param lines The number of lines
+ */
+ public void insertLines(int index, int lines)
+ {
+ if(lines <= 0)
+ return;
+ length += lines;
+ ensureCapacity(length);
+ int len = index + lines;
+ System.arraycopy(lineInfo,index,lineInfo,len,
+ lineInfo.length - len);
+
+ for(int i = index + lines - 1; i >= index; i--)
+ {
+ lineInfo[i] = new LineInfo();
+ }
+ }
+
+ /**
+ * Informs the token marker that line have been deleted from
+ * the document. This removes the lines in question from the
+ * lineInfo array.
+ * @param index The first line number
+ * @param lines The number of lines
+ */
+ public void deleteLines(int index, int lines)
+ {
+ if (lines <= 0)
+ return;
+ int len = index + lines;
+ length -= lines;
+ System.arraycopy(lineInfo,len,lineInfo,
+ index,lineInfo.length - len);
+ }
+
+ /**
+ * Returns the number of lines in this token marker.
+ */
+ public int getLineCount()
+ {
+ return length;
+ }
+
+ /**
+ * Returns true if the next line should be repainted. This
+ * will return true after a line has been tokenized that starts
+ * a multiline token that continues onto the next line.
+ */
+ public boolean isNextLineRequested()
+ {
+ return nextLineRequested;
+ }
+
+ // protected members
+
+ /**
+ * The first token in the list. This should be used as the return
+ * value from markTokens().
+ */
+ protected Token firstToken;
+
+ /**
+ * The last token in the list. New tokens are added here.
+ * This should be set to null before a new line is to be tokenized.
+ */
+ protected Token lastToken;
+
+ /**
+ * An array for storing information about lines. It is enlarged and
+ * shrunk automatically by the insertLines() and
+ * deleteLines() methods.
+ */
+ protected LineInfo[] lineInfo;
+
+ /**
+ * The number of lines in the model being tokenized. This can be
+ * less than the length of the lineInfo array.
+ */
+ protected int length;
+
+ /**
+ * The last tokenized line.
+ */
+ protected int lastLine;
+
+ /**
+ * True if the next line should be painted.
+ */
+ protected boolean nextLineRequested;
+
+ /**
+ * Creates a new TokenMarker. This DOES NOT create
+ * a lineInfo array; an initial call to insertLines()
+ * does that.
+ */
+ protected TokenMarker()
+ {
+ lastLine = -1;
+ }
+
+ /**
+ * Ensures that the lineInfo array can contain the
+ * specified index. This enlarges it if necessary. No action is
+ * taken if the array is large enough already.
+ *
+ * It should be unnecessary to call this under normal
+ * circumstances; insertLine() should take care of
+ * enlarging the line info array automatically.
+ *
+ * @param index The array index
+ */
+ protected void ensureCapacity(int index)
+ {
+ if(lineInfo == null)
+ lineInfo = new LineInfo[index + 1];
+ else if(lineInfo.length <= index)
+ {
+ LineInfo[] lineInfoN = new LineInfo[(index + 1) * 2];
+ System.arraycopy(lineInfo,0,lineInfoN,0,
+ lineInfo.length);
+ lineInfo = lineInfoN;
+ }
+ }
+
+ /**
+ * Adds a token to the token list.
+ * @param length The length of the token
+ * @param id The id of the token
+ */
+ protected void addToken(int length, byte id)
+ {
+ if(id >= Token.INTERNAL_FIRST && id <= Token.INTERNAL_LAST)
+ throw new InternalError("Invalid id: " + id);
+
+ if(length == 0 && id != Token.END)
+ return;
+
+ if(firstToken == null)
+ {
+ firstToken = new Token(length,id);
+ lastToken = firstToken;
+ }
+ else if(lastToken == null)
+ {
+ lastToken = firstToken;
+ firstToken.length = length;
+ firstToken.id = id;
+ }
+ else if(lastToken.next == null)
+ {
+ lastToken.next = new Token(length,id);
+ lastToken = lastToken.next;
+ }
+ else
+ {
+ lastToken = lastToken.next;
+ lastToken.length = length;
+ lastToken.id = id;
+ }
+ }
+
+ /**
+ * Inner class for storing information about tokenized lines.
+ */
+ public class LineInfo
+ {
+ /**
+ * Creates a new LineInfo object with token = Token.NULL
+ * and obj = null.
+ */
+ public LineInfo()
+ {
+ }
+
+ /**
+ * Creates a new LineInfo object with the specified
+ * parameters.
+ */
+ public LineInfo(byte token, Object obj)
+ {
+ this.token = token;
+ this.obj = obj;
+ }
+
+ /**
+ * The id of the last token of the line.
+ */
+ public byte token;
+
+ /**
+ * This is for use by the token marker implementations
+ * themselves. It can be used to store anything that
+ * is an object and that needs to exist on a per-line
+ * basis.
+ */
+ public Object obj;
+ }
+}
diff --git a/app/src/processing/app/syntax/readme.txt b/app/src/processing/app/syntax/readme.txt
new file mode 100644
index 000000000..07a825cd7
--- /dev/null
+++ b/app/src/processing/app/syntax/readme.txt
@@ -0,0 +1,46 @@
+OLDSYNTAX PACKAGE README
+
+I am placing the jEdit 2.2.1 syntax highlighting package in the public
+domain. This means it can be integrated into commercial programs, etc.
+
+This package requires at least Java 1.1 and Swing 1.1. Syntax
+highlighting for the following file types is supported:
+
+- C++, C
+- CORBA IDL
+- Eiffel
+- HTML
+- Java
+- Java properties
+- JavaScript
+- MS-DOS INI
+- MS-DOS batch files
+- Makefile
+- PHP
+- Perl
+- Python
+- TeX
+- Transact-SQL
+- Unix patch/diff
+- Unix shell script
+- XML
+
+This package is undocumented; read the source (start by taking a look at
+JEditTextArea.java) to find out how to use it; it's really simple. Feel
+free to e-mail questions, queries, etc. to me, but keep in mind that
+this code is very old and I no longer maintain it. So if you find a bug,
+don't bother me about it; fix it yourself.
+
+* Copyright
+
+The jEdit 2.2.1 syntax highlighting package contains code that is
+Copyright 1998-1999 Slava Pestov, Artur Biesiadowski, Clancy Malcolm,
+Jonathan Revusky, Juha Lindfors and Mike Dillon.
+
+You may use and modify this package for any purpose. Redistribution is
+permitted, in both source and binary form, provided that this notice
+remains intact in all source distributions of this package.
+
+-- Slava Pestov
+25 September 2000
+
diff --git a/app/src/processing/app/tools/Archiver.java b/app/src/processing/app/tools/Archiver.java
new file mode 100755
index 000000000..9eb9655ff
--- /dev/null
+++ b/app/src/processing/app/tools/Archiver.java
@@ -0,0 +1,184 @@
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+/*
+ Archiver - plugin tool for archiving sketches
+ Part of the Processing project - http://processing.org
+
+ Copyright (c) 2004-06 Ben Fry and Casey Reas
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+package processing.app.tools;
+
+import processing.app.*;
+
+import java.awt.FileDialog;
+import java.io.*;
+import java.text.*;
+import java.util.*;
+import java.util.zip.*;
+
+
+public class Archiver implements Tool {
+ Editor editor;
+
+ // someday these will be settable
+ boolean useDate;
+ int digits = 3;
+
+ NumberFormat numberFormat;
+ SimpleDateFormat dateFormat;
+
+
+ public String getMenuTitle() {
+ return "Archive Sketch";
+ }
+
+
+ public void init(Editor editor) {
+ this.editor = editor;
+
+ numberFormat = NumberFormat.getInstance();
+ numberFormat.setGroupingUsed(false); // no commas
+ numberFormat.setMinimumIntegerDigits(digits);
+
+ dateFormat = new SimpleDateFormat("yyMMdd");
+ }
+
+
+ public void run() {
+ Sketch sketch = editor.getSketch();
+
+ // first save the sketch so that things don't archive strangely
+ boolean success = false;
+ try {
+ success = sketch.save();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ if (!success) {
+ Base.showWarning("Couldn't archive sketch",
+ "Archiving the sketch has been canceled because\n" +
+ "the sketch couldn't save properly.", null);
+ return;
+ }
+
+ File location = sketch.getFolder();
+ String name = location.getName();
+ File parent = new File(location.getParent());
+
+ //System.out.println("loc " + location);
+ //System.out.println("par " + parent);
+
+ File newbie = null;
+ String namely = null;
+ int index = 0;
+ do {
+ // only use the date if the sketch name isn't the default name
+ useDate = !name.startsWith("sketch_");
+
+ if (useDate) {
+ String purty = dateFormat.format(new Date());
+ String stamp = purty + ((char) ('a' + index));
+ namely = name + "-" + stamp;
+ newbie = new File(parent, namely + ".zip");
+
+ } else {
+ String diggie = numberFormat.format(index + 1);
+ namely = name + "-" + diggie;
+ newbie = new File(parent, namely + ".zip");
+ }
+ index++;
+ } while (newbie.exists());
+
+ // open up a prompt for where to save this fella
+ FileDialog fd =
+ new FileDialog(editor, "Archive sketch as:", FileDialog.SAVE);
+ fd.setDirectory(parent.getAbsolutePath());
+ fd.setFile(newbie.getName());
+ fd.setVisible(true);
+
+ String directory = fd.getDirectory();
+ String filename = fd.getFile();
+
+ // only write the file if not canceled
+ if (filename != null) {
+ newbie = new File(directory, filename);
+
+ try {
+ //System.out.println(newbie);
+ FileOutputStream zipOutputFile = new FileOutputStream(newbie);
+ ZipOutputStream zos = new ZipOutputStream(zipOutputFile);
+
+ // recursively fill the zip file
+ buildZip(location, name, zos);
+
+ // close up the jar file
+ zos.flush();
+ zos.close();
+
+ editor.statusNotice("Created archive " + newbie.getName() + ".");
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ } else {
+ editor.statusNotice("Archive sketch canceled.");
+ }
+ }
+
+
+ public void buildZip(File dir, String sofar,
+ ZipOutputStream zos) throws IOException {
+ String files[] = dir.list();
+ for (int i = 0; i < files.length; i++) {
+ if (files[i].equals(".") ||
+ files[i].equals("..")) continue;
+
+ File sub = new File(dir, files[i]);
+ String nowfar = (sofar == null) ?
+ files[i] : (sofar + "/" + files[i]);
+
+ if (sub.isDirectory()) {
+ // directories are empty entries and have / at the end
+ ZipEntry entry = new ZipEntry(nowfar + "/");
+ //System.out.println(entry);
+ zos.putNextEntry(entry);
+ zos.closeEntry();
+ buildZip(sub, nowfar, zos);
+
+ } else {
+ ZipEntry entry = new ZipEntry(nowfar);
+ entry.setTime(sub.lastModified());
+ zos.putNextEntry(entry);
+ zos.write(Base.loadBytesRaw(sub));
+ zos.closeEntry();
+ }
+ }
+ }
+}
+
+
+ /*
+ int index = 0;
+ SimpleDateFormat formatter = new SimpleDateFormat("yyMMdd");
+ String purty = formatter.format(new Date());
+ do {
+ newbieName = "sketch_" + purty + ((char) ('a' + index));
+ newbieDir = new File(newbieParentDir, newbieName);
+ index++;
+ } while (newbieDir.exists());
+ */
diff --git a/app/src/processing/app/tools/AutoFormat.java b/app/src/processing/app/tools/AutoFormat.java
new file mode 100644
index 000000000..2397967c5
--- /dev/null
+++ b/app/src/processing/app/tools/AutoFormat.java
@@ -0,0 +1,946 @@
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+/*
+ Part of the Processing project - http://processing.org
+
+ Copyright (c) 2005-06 Ben Fry and Casey Reas
+ Copyright (c) 2003 Martin Gomez, Ateneo de Manila University
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+package processing.app.tools;
+
+import processing.app.*;
+
+import java.io.*;
+
+
+/**
+ * Alternate handler for dealing with auto format.
+ * Contributed by Martin Gomez, additional bug fixes by Ben Fry.
+ */
+public class AutoFormat implements Tool {
+ Editor editor;
+
+ static final int BLOCK_MAXLEN = 1024;
+
+ StringBuffer strOut;
+ //String formattedText;
+ int indentValue;
+ String indentChar;
+ //String uhOh = null;
+ //String theStuff;
+ int EOF;
+ BufferedInputStream bin = null;
+ int nBytesRead, indexBlock, lineLength, lineNumber;
+ byte bArray[];
+ String strBlock;
+ int s_level[];
+ int c_level;
+ int sp_flg[][];
+ int s_ind[][];
+ int s_if_lev[];
+ int s_if_flg[];
+ int if_lev, if_flg, level;
+ int ind[];
+ int e_flg, paren;
+ static int p_flg[];
+ char l_char, p_char;
+ int a_flg, q_flg, ct;
+ int s_tabs[][];
+ String w_if_, w_else, w_for, w_ds, w_case, w_cpp_comment, w_jdoc;
+ int jdoc, j;
+ char string[];
+ byte bstring[];
+ byte bblank;
+ char cc;
+ int s_flg, b_flg;
+ int peek;
+ char peekc;
+ int tabs;
+ char next_char, last_char;
+ char lastc0, lastc1;
+ char c, c0;
+ char w_kptr;
+
+ String line_feed;
+
+ //static int outfil; // temporary
+
+
+ public void init(Editor editor) {
+ this.editor = editor;
+ }
+
+
+ public String getMenuTitle() {
+ return "Auto Format";
+ }
+
+ public void comment() throws IOException {
+ int save_s_flg;
+ save_s_flg = s_flg;
+
+ int done = 0;
+ c = string[j++] = getchr(); // extra char
+ while (done == 0) {
+ c = string[j++] = getchr();
+ while ((c != '/') && (j < string.length)) {
+ if(c == '\n' || c == '\r') {
+ lineNumber++;
+ putcoms();
+ s_flg = 1;
+ }
+ c = string[j++] = getchr();
+ }
+ //String tmpstr = new String(string);
+ if (j>1 && string[j-2] == '*') {
+ done = 1;
+ jdoc = 0;
+ }
+ }
+
+ putcoms();
+ s_flg = save_s_flg;
+ jdoc = 0;
+ return;
+ }
+
+
+ public char get_string() throws IOException {
+ char ch;
+ ch = '*';
+ while (true) {
+ switch (ch) {
+ default:
+ ch = string[j++] = getchr();
+ if (ch == '\\') {
+ string[j++] = getchr();
+ break;
+ }
+ if (ch == '\'' || ch == '"') {
+ cc = string[j++] = getchr();
+ while (cc != ch) {
+ if (cc == '\\') string[j++] = getchr();
+ cc = string[j++] = getchr();
+ }
+ break;
+ }
+ if (ch == '\n' || ch == '\r') {
+ indent_puts();
+ a_flg = 1;
+ break;
+ } else {
+ return(ch);
+ }
+ }
+ }
+ }
+
+
+ public void indent_puts() {
+ string[j] = '\0';
+ if (j > 0) {
+ if (s_flg != 0) {
+ if((tabs > 0) && (string[0] != '{') && (a_flg == 1)) {
+ tabs++;
+ }
+ p_tabs();
+ s_flg = 0;
+ if ((tabs > 0) && (string[0] != '{') && (a_flg == 1)) {
+ tabs--;
+ }
+ a_flg = 0;
+ }
+ String j_string = new String(string);
+ strOut.append(j_string.substring(0,j));
+ for (int i=0; i 0)
+ {
+ if(s_flg != 0)
+ {
+ p_tabs();
+ s_flg = 0;
+ }
+ string[j] = '\0';
+ i = 0;
+ while (string[i] == ' ') i++;
+ if (lookup_com(w_jdoc) == 1) jdoc = 1;
+ String strBuffer = new String(string,0,j);
+ if (string[i] == '/' && string[i+1]=='*')
+ {
+ if ((last_char != ';') && (sav_s_flg==1) )
+ {
+ //fprintf(outfil, strBuffer.substring(i,j));
+ fprintf(strBuffer.substring(i,j));
+ }
+ else
+ {
+ //fprintf(outfil, strBuffer);
+ fprintf(strBuffer);
+ }
+ }
+ else
+ {
+ if (string[i]=='*' || jdoc == 0)
+ //fprintf (outfil, " "+strBuffer.substring(i,j));
+ fprintf (" "+strBuffer.substring(i,j));
+ else
+ //fprintf (outfil, " * "+strBuffer.substring(i,j));
+ fprintf (" * "+strBuffer.substring(i,j));
+ }
+ j = 0;
+ string[0] = '\0';
+ }
+ }
+
+ public void cpp_comment() throws IOException
+ {
+ c = getchr();
+ while(c != '\n' && c != '\r' && j<133)
+ {
+ string[j++] = c;
+ c = getchr();
+ }
+ lineNumber++;
+ indent_puts();
+ s_flg = 1;
+ }
+
+
+ /* expand indentValue into tabs and spaces */
+ public void p_tabs()
+ {
+ int i,k;
+
+ if (tabs<0) tabs = 0;
+ if (tabs==0) return;
+ i = tabs * indentValue; // calc number of spaces
+ //j = i/8; /* calc number of tab chars */
+
+ for (k=0; k < i; k++) {
+ strOut.append(indentChar);
+ }
+ }
+
+
+ public char getchr() throws IOException
+ {
+ if((peek < 0) && (last_char != ' ') && (last_char != '\t'))
+ {
+ if((last_char != '\n') && (last_char != '\r'))
+ p_char = last_char;
+ }
+ if(peek > 0) /* char was read previously */
+ {
+ last_char = peekc;
+ peek = -1;
+ }
+ else /* read next char in string */
+ {
+ indexBlock++;
+ if (indexBlock >= lineLength)
+ {
+ for (int ib=0; ib 0)
+ {
+ nBytesRead = bin.read(bArray);
+ lineLength = nBytesRead;
+ strBlock = new String(bArray);
+ indexBlock = 0;
+ last_char = strBlock.charAt(indexBlock);
+ peek = -1;
+ peekc = '`';
+ }
+ else
+ {
+ //System.out.println("eof a");
+ EOF = 1;
+ peekc = '\0';
+ }
+ //}
+ //catch(IOException ioe)
+ //{
+ //System.out.println(ioe.toString());
+ //}
+ }
+ else
+ {
+ last_char = strBlock.charAt(indexBlock);
+ }
+ }
+ peek = -1;
+ if (last_char == '\r')
+ {
+ last_char = getchr();
+ }
+
+ return last_char;
+ }
+
+ /* else processing */
+ public void gotelse()
+ {
+ tabs = s_tabs[c_level][if_lev];
+ p_flg[level] = sp_flg[c_level][if_lev];
+ ind[level] = s_ind[c_level][if_lev];
+ if_flg = 1;
+ }
+
+ /* read to new_line */
+ public int getnl() throws IOException
+ {
+ int save_s_flg;
+ save_s_flg = tabs;
+ peekc = getchr();
+ //while ((peekc == '\t' || peekc == ' ') &&
+ // (j < string.length)) {
+ while (peekc == '\t' || peekc == ' ') {
+ string[j++] = peekc;
+ peek = -1;
+ peekc = '`';
+ peekc = getchr();
+ peek = 1;
+ }
+ peek = 1;
+
+ if (peekc == '/')
+ {
+ peek = -1;
+ peekc = '`';
+ peekc = getchr();
+ if (peekc == '*')
+ {
+ string[j++] = '/';
+ string[j++] = '*';
+ peek = -1;
+ peekc = '`';
+ comment();
+ }
+ else if (peekc == '/')
+ {
+ string[j++] = '/';
+ string[j++] = '/';
+ peek = -1;
+ peekc = '`';
+ cpp_comment();
+ return (1);
+ }
+ else
+ {
+ string[j++] = '/';
+ peek = 1;
+ }
+ }
+ peekc = getchr();
+ if(peekc == '\n')
+ {
+ lineNumber++;
+ peek = -1;
+ peekc = '`';
+ tabs = save_s_flg;
+ return(1);
+ }
+ else
+ {
+ peek = 1;
+ }
+ return 0;
+ }
+
+ public int lookup (String keyword)
+ {
+ char r;
+ int l,kk; //,k,i;
+ String j_string = new String(string);
+
+ if (j<1) return (0);
+ kk=0;
+ while(string[kk] == ' ')kk++;
+ l=0;
+ l = j_string.indexOf(keyword);
+ if (l<0 || l!=kk)
+ {
+ return 0;
+ }
+ r = string[kk+keyword.length()];
+ if(r >= 'a' && r <= 'z') return(0);
+ if(r >= 'A' && r <= 'Z') return(0);
+ if(r >= '0' && r <= '9') return(0);
+ if(r == '_' || r == '&') return(0);
+ return (1);
+ }
+
+ public int lookup_com (String keyword)
+ {
+ //char r;
+ int l,kk; //,k,i;
+ String j_string = new String(string);
+
+ if (j<1) return (0);
+ kk=0;
+ while(string[kk] == ' ')kk++;
+ l=0;
+ l = j_string.indexOf(keyword);
+ if (l<0 || l!=kk)
+ {
+ return 0;
+ }
+ return (1);
+ }
+
+
+ public void run() {
+ StringBuffer onechar;
+
+ // Adding an additional newline as a hack around other errors
+ String originalText = editor.getText() + "\n";
+ strOut = new StringBuffer();
+ indentValue = Preferences.getInteger("editor.tabs.size");
+ indentChar = new String(" ");
+
+ lineNumber = 0;
+ //BLOCK_MAXLEN = 256;
+ c_level = if_lev = level = e_flg = paren = 0;
+ a_flg = q_flg = j = b_flg = tabs = 0;
+ if_flg = peek = -1;
+ peekc = '`';
+ s_flg = 1;
+ bblank = ' ';
+ jdoc = 0;
+
+ s_level = new int[10];
+ sp_flg = new int[20][10];
+ s_ind = new int[20][10];
+ s_if_lev = new int[10];
+ s_if_flg = new int[10];
+ ind = new int[10];
+ p_flg = new int[10];
+ s_tabs = new int[20][10];
+
+ w_else = new String ("else");
+ w_if_ = new String ("if");
+ w_for = new String ("for");
+ w_ds = new String ("default");
+ w_case = new String ("case");
+ w_cpp_comment = new String ("//");
+ w_jdoc = new String ("/**");
+ line_feed = new String ("\n");
+
+ // read as long as there is something to read
+ EOF = 0; // = 1 set in getchr when EOF
+
+ bArray = new byte[BLOCK_MAXLEN];
+ string = new char[BLOCK_MAXLEN];
+ try { // the whole process
+ // open for input
+ ByteArrayInputStream in =
+ new ByteArrayInputStream(originalText.getBytes());
+
+ // add buffering to that InputStream
+ bin = new BufferedInputStream(in);
+
+ for (int ib = 0; ib < BLOCK_MAXLEN; ib++) bArray[ib] = '\0';
+
+ lineLength = nBytesRead = 0;
+ // read up a block - remember how many bytes read
+ nBytesRead = bin.read(bArray);
+ strBlock = new String(bArray);
+
+ lineLength = nBytesRead;
+ lineNumber = 1;
+ indexBlock = -1;
+ j = 0;
+ while (EOF == 0)
+ {
+ c = getchr();
+ switch(c)
+ {
+ default:
+ string[j++] = c;
+ if(c != ',')
+ {
+ l_char = c;
+ }
+ break;
+
+ case ' ':
+ case '\t':
+ if(lookup(w_else) == 1)
+ {
+ gotelse();
+ if(s_flg == 0 || j > 0)string[j++] = c;
+ indent_puts();
+ s_flg = 0;
+ break;
+ }
+ if(s_flg == 0 || j > 0)string[j++] = c;
+ break;
+
+ case '\r': // for MS Windows 95
+ case '\n':
+ lineNumber++;
+ if (EOF==1)
+ {
+ break;
+ }
+ //String j_string = new String(string);
+
+ e_flg = lookup(w_else);
+ if(e_flg == 1) gotelse();
+ if (lookup_com(w_cpp_comment) == 1)
+ {
+ if (string[j] == '\n')
+ {
+ string[j] = '\0';
+ j--;
+ }
+ }
+
+ indent_puts();
+ //fprintf(outfil, line_feed);
+ fprintf(line_feed);
+ s_flg = 1;
+ if(e_flg == 1)
+ {
+ p_flg[level]++;
+ tabs++;
+ }
+ else
+ if(p_char == l_char)
+ {
+ a_flg = 1;
+ }
+ break;
+
+ case '{':
+ if(lookup(w_else) == 1)gotelse();
+ s_if_lev[c_level] = if_lev;
+ s_if_flg[c_level] = if_flg;
+ if_lev = if_flg = 0;
+ c_level++;
+ if(s_flg == 1 && p_flg[level] != 0)
+ {
+ p_flg[level]--;
+ tabs--;
+ }
+ string[j++] = c;
+ indent_puts();
+ getnl() ;
+ indent_puts();
+ //fprintf(outfil,"\n");
+ fprintf("\n");
+ tabs++;
+ s_flg = 1;
+ if(p_flg[level] > 0)
+ {
+ ind[level] = 1;
+ level++;
+ s_level[level] = c_level;
+ }
+ break;
+
+ case '}':
+ c_level--;
+ if (c_level < 0)
+ {
+ EOF = 1;
+ //System.out.println("eof b");
+ string[j++] = c;
+ indent_puts();
+ break;
+ }
+ if ((if_lev = s_if_lev[c_level]-1) < 0)
+ if_lev = 0;
+ if_flg = s_if_flg[c_level];
+ indent_puts();
+ tabs--;
+ p_tabs();
+ peekc = getchr();
+ if( peekc == ';')
+ {
+ onechar = new StringBuffer();
+ onechar.append(c); // the }
+ onechar.append(';');
+ //fprintf(outfil, onechar.toString());
+ fprintf(onechar.toString());
+ peek = -1;
+ peekc = '`';
+ }
+ else
+ {
+ onechar = new StringBuffer();
+ onechar.append(c);
+ //fprintf(outfil, onechar.toString());
+ fprintf(onechar.toString());
+ peek = 1;
+ }
+ getnl();
+ indent_puts();
+ //fprintf(outfil,"\n");
+ fprintf("\n");
+ s_flg = 1;
+ if(c_level < s_level[level])
+ if(level > 0) level--;
+ if(ind[level] != 0)
+ {
+ tabs -= p_flg[level];
+ p_flg[level] = 0;
+ ind[level] = 0;
+ }
+ break;
+
+ case '"':
+ case '\'':
+ string[j++] = c;
+ cc = getchr();
+ while(cc != c)
+ {
+ // max. length of line should be 256
+ string[j++] = cc;
+
+ if(cc == '\\')
+ {
+ cc = string[j++] = getchr();
+ }
+ if(cc == '\n')
+ {
+ lineNumber++;
+ indent_puts();
+ s_flg = 1;
+ }
+ cc = getchr();
+
+ }
+ string[j++] = cc;
+ if(getnl() == 1)
+ {
+ l_char = cc;
+ peek = 1;
+ peekc = '\n';
+ }
+ break;
+
+ case ';':
+ string[j++] = c;
+ indent_puts();
+ if(p_flg[level] > 0 && ind[level] == 0)
+ {
+ tabs -= p_flg[level];
+ p_flg[level] = 0;
+ }
+ getnl();
+ indent_puts();
+ //fprintf(outfil,"\n");
+ fprintf("\n");
+ s_flg = 1;
+ if(if_lev > 0)
+ if(if_flg == 1)
+ {
+ if_lev--;
+ if_flg = 0;
+ }
+ else if_lev = 0;
+ break;
+
+ case '\\':
+ string[j++] = c;
+ string[j++] = getchr();
+ break;
+
+ case '?':
+ q_flg = 1;
+ string[j++] = c;
+ break;
+
+ case ':':
+ string[j++] = c;
+ peekc = getchr();
+ if(peekc == ':')
+ {
+ indent_puts();
+ //fprintf (outfil,":");
+ fprintf(":");
+ peek = -1;
+ peekc = '`';
+ break;
+ }
+ else
+ {
+ //int double_colon = 0;
+ peek = 1;
+ }
+
+ if(q_flg == 1)
+ {
+ q_flg = 0;
+ break;
+ }
+ if(lookup(w_ds) == 0 && lookup(w_case) == 0)
+ {
+ s_flg = 0;
+ indent_puts();
+ }
+ else
+ {
+ tabs--;
+ indent_puts();
+ tabs++;
+ }
+ peekc = getchr();
+ if(peekc == ';')
+ {
+ //fprintf(outfil,";");
+ fprintf(";");
+ peek = -1;
+ peekc = '`';
+ }
+ else
+ {
+ peek = 1;
+ }
+ getnl();
+ indent_puts();
+ //fprintf(outfil,"\n");
+ fprintf("\n");
+ s_flg = 1;
+ break;
+
+ case '/':
+ c0 = string[j];
+ string[j++] = c;
+ peekc = getchr();
+
+ if(peekc == '/')
+ {
+ string[j++] = peekc;
+ peekc = '`';
+ peek = -1;
+ cpp_comment();
+ //fprintf(outfil,"\n");
+ fprintf("\n");
+ break;
+ }
+ else
+ {
+ peek = 1;
+ }
+
+ if(peekc != '*') {
+ break;
+ }
+ else
+ {
+ if (j > 0) string[j--] = '\0';
+ if (j > 0) indent_puts();
+ string[j++] = '/';
+ string[j++] = '*';
+ peek = -1;
+ peekc = '`';
+ comment();
+ break;
+ }
+
+ case '#':
+ string[j++] = c;
+ cc = getchr();
+ while(cc != '\n')
+ {
+ string[j++] = cc;
+ cc = getchr();
+ }
+ string[j++] = cc;
+ s_flg = 0;
+ indent_puts();
+ s_flg = 1;
+ break;
+
+ case ')':
+ paren--;
+ if (paren < 0)
+ {
+ EOF = 1;
+ //System.out.println("eof c");
+ }
+ string[j++] = c;
+ indent_puts();
+ if(getnl() == 1)
+ {
+ peekc = '\n';
+ peek = 1;
+ if(paren != 0)
+ {
+ a_flg = 1;
+ }
+ else if(tabs > 0)
+ {
+ p_flg[level]++;
+ tabs++;
+ ind[level] = 0;
+ }
+ }
+ break;
+
+ case '(':
+ string[j++] = c;
+ paren++;
+ if ((lookup(w_for) == 1))
+ {
+ c = get_string();
+ while(c != ';') c = get_string();
+ ct=0;
+ int for_done = 0;
+ while (for_done==0)
+ {
+ c = get_string();
+ while(c != ')')
+ {
+ if(c == '(') ct++;
+ c = get_string();
+ }
+ if(ct != 0)
+ {
+ ct--;
+ }
+ else for_done = 1;
+ } // endwhile for_done
+ paren--;
+ if (paren < 0)
+ {
+ EOF = 1;
+ //System.out.println("eof d");
+ }
+ indent_puts();
+ if(getnl() == 1)
+ {
+ peekc = '\n';
+ peek = 1;
+ p_flg[level]++;
+ tabs++;
+ ind[level] = 0;
+ }
+ break;
+ }
+
+ if(lookup(w_if_) == 1)
+ {
+ indent_puts();
+ s_tabs[c_level][if_lev] = tabs;
+ sp_flg[c_level][if_lev] = p_flg[level];
+ s_ind[c_level][if_lev] = ind[level];
+ if_lev++;
+ if_flg = 1;
+ }
+ } // end switch
+
+ //System.out.println("string len is " + string.length);
+ //if (EOF == 1) System.out.println(string);
+ //String j_string = new String(string);
+
+ } // end while not EOF
+
+ /*
+ int bad;
+ while ((bad = bin.read()) != -1) {
+ System.out.print((char) bad);
+ }
+ */
+ /*
+ char bad;
+ //while ((bad = getchr()) != 0) {
+ while (true) {
+ getchr();
+ if (peek != -1) {
+ System.out.print(last_char);
+ } else {
+ break;
+ }
+ }
+ */
+
+ // save current (rough) selection point
+ int selectionEnd = editor.getSelectionStop();
+
+ // make sure the caret would be past the end of the text
+ if (strOut.length() < selectionEnd - 1) {
+ selectionEnd = strOut.length() - 1;
+ }
+
+ bin.close(); // close buff
+
+ String formattedText = strOut.toString();
+ if (formattedText.equals(originalText)) {
+ editor.statusNotice("No changes necessary for Auto Format.");
+
+ } else if (paren != 0) {
+ // warn user if there are too many parens in either direction
+ editor.statusError("Auto Format Canceled: Too many " +
+ ((paren < 0) ? "right" : "left") +
+ " parentheses.");
+
+ } else if (c_level != 0) { // check braces only if parens are ok
+ editor.statusError("Auto Format Canceled: Too many " +
+ ((c_level < 0) ? "right" : "left") +
+ " curly braces.");
+
+ } else {
+ // replace with new bootiful text
+ // selectionEnd hopefully at least in the neighborhood
+ editor.setText(formattedText);
+ editor.setSelection(selectionEnd, selectionEnd);
+ editor.getSketch().setModified(true);
+ // mark as finished
+ editor.statusNotice("Auto Format finished.");
+ }
+
+ } catch (Exception e) {
+ editor.statusError(e);
+ }
+ }
+}
diff --git a/app/src/processing/app/tools/ColorSelector.java b/app/src/processing/app/tools/ColorSelector.java
new file mode 100644
index 000000000..d4843d18a
--- /dev/null
+++ b/app/src/processing/app/tools/ColorSelector.java
@@ -0,0 +1,596 @@
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+/*
+ Part of the Processing project - http://processing.org
+
+ Copyright (c) 2006-08 Ben Fry and Casey Reas
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+package processing.app.tools;
+
+import processing.app.*;
+import processing.core.*;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.event.*;
+import javax.swing.text.*;
+
+
+/**
+ * Color selector tool for the Tools menu.
+ *
+ * Using the keyboard shortcuts, you can copy/paste the values for the
+ * colors and paste them into your program. We didn't do any sort of
+ * auto-insert of colorMode() or fill() or stroke() code cuz we couldn't
+ * decide on a good way to do this.. your contributions welcome).
+ */
+public class ColorSelector implements Tool, DocumentListener {
+
+ Editor editor;
+ JFrame frame;
+
+ int hue, saturation, brightness; // range 360, 100, 100
+ int red, green, blue; // range 256, 256, 256
+
+ ColorRange range;
+ ColorSlider slider;
+
+ JTextField hueField, saturationField, brightnessField;
+ JTextField redField, greenField, blueField;
+
+ JTextField hexField;
+
+ JPanel colorPanel;
+
+
+ public String getMenuTitle() {
+ return "Color Selector";
+ }
+
+
+ public void init(Editor editor) {
+ this.editor = editor;
+
+ frame = new JFrame("Color Selector");
+ frame.getContentPane().setLayout(new BorderLayout());
+
+ Box box = Box.createHorizontalBox();
+ box.setBorder(new EmptyBorder(12, 12, 12, 12));
+
+ range = new ColorRange();
+ range.init();
+ Box rangeBox = new Box(BoxLayout.Y_AXIS);
+ rangeBox.setAlignmentY(0);
+ rangeBox.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
+ rangeBox.add(range);
+ box.add(rangeBox);
+ box.add(Box.createHorizontalStrut(10));
+
+ slider = new ColorSlider();
+ slider.init();
+ Box sliderBox = new Box(BoxLayout.Y_AXIS);
+ sliderBox.setAlignmentY(0);
+ sliderBox.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
+ sliderBox.add(slider);
+ box.add(sliderBox);
+ box.add(Box.createHorizontalStrut(10));
+
+ box.add(createColorFields());
+ box.add(Box.createHorizontalStrut(10));
+
+ frame.getContentPane().add(box, BorderLayout.CENTER);
+ frame.pack();
+ frame.setResizable(false);
+
+ // these don't help either.. they fix the component size but
+ // leave a gap where the component is located
+ //range.setSize(256, 256);
+ //slider.setSize(256, 20);
+
+ Dimension size = frame.getSize();
+ Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
+ frame.setLocation((screen.width - size.width) / 2,
+ (screen.height - size.height) / 2);
+
+ frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
+ frame.addWindowListener(new WindowAdapter() {
+ public void windowClosing(WindowEvent e) {
+ frame.setVisible(false);
+ }
+ });
+ Base.registerWindowCloseKeys(frame.getRootPane(), new ActionListener() {
+ public void actionPerformed(ActionEvent actionEvent) {
+ frame.setVisible(false);
+ }
+ });
+ Base.setIcon(frame);
+
+ hueField.getDocument().addDocumentListener(this);
+ saturationField.getDocument().addDocumentListener(this);
+ brightnessField.getDocument().addDocumentListener(this);
+ redField.getDocument().addDocumentListener(this);
+ greenField.getDocument().addDocumentListener(this);
+ blueField.getDocument().addDocumentListener(this);
+ hexField.getDocument().addDocumentListener(this);
+
+ hexField.setText("FFFFFF");
+ }
+
+
+ public void run() {
+ frame.setVisible(true);
+ // You've got to be f--ing kidding me.. why did the following line
+ // get deprecated for the pile of s-- that follows it?
+ //frame.setCursor(Cursor.CROSSHAIR_CURSOR);
+ frame.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
+ }
+
+
+ public void changedUpdate(DocumentEvent e) {
+ //System.out.println("changed");
+ }
+
+ public void removeUpdate(DocumentEvent e) {
+ //System.out.println("remove");
+ }
+
+
+ boolean updating;
+
+ public void insertUpdate(DocumentEvent e) {
+ if (updating) return; // don't update forever recursively
+ updating = true;
+
+ Document doc = e.getDocument();
+ if (doc == hueField.getDocument()) {
+ hue = bounded(hue, hueField, 359);
+ updateRGB();
+ updateHex();
+
+ } else if (doc == saturationField.getDocument()) {
+ saturation = bounded(saturation, saturationField, 99);
+ updateRGB();
+ updateHex();
+
+ } else if (doc == brightnessField.getDocument()) {
+ brightness = bounded(brightness, brightnessField, 99);
+ updateRGB();
+ updateHex();
+
+ } else if (doc == redField.getDocument()) {
+ red = bounded(red, redField, 255);
+ updateHSB();
+ updateHex();
+
+ } else if (doc == greenField.getDocument()) {
+ green = bounded(green, greenField, 255);
+ updateHSB();
+ updateHex();
+
+ } else if (doc == blueField.getDocument()) {
+ blue = bounded(blue, blueField, 255);
+ updateHSB();
+ updateHex();
+
+ } else if (doc == hexField.getDocument()) {
+ String str = hexField.getText();
+ while (str.length() < 6) {
+ str += "0";
+ }
+ if (str.length() > 6) {
+ str = str.substring(0, 6);
+ }
+ updateRGB2(Integer.parseInt(str, 16));
+ updateHSB();
+ }
+ range.redraw();
+ slider.redraw();
+ colorPanel.repaint();
+ updating = false;
+ }
+
+
+ /**
+ * Set the RGB values based on the current HSB values.
+ */
+ protected void updateRGB() {
+ int rgb = Color.HSBtoRGB((float)hue / 359f,
+ (float)saturation / 99f,
+ (float)brightness / 99f);
+ updateRGB2(rgb);
+ }
+
+
+ /**
+ * Set the RGB values based on a calculated ARGB int.
+ * Used by both updateRGB() to set the color from the HSB values,
+ * and by updateHex(), to unpack the hex colors and assign them.
+ */
+ protected void updateRGB2(int rgb) {
+ red = (rgb >> 16) & 0xff;
+ green = (rgb >> 8) & 0xff;
+ blue = rgb & 0xff;
+
+ redField.setText(String.valueOf(red));
+ greenField.setText(String.valueOf(green));
+ blueField.setText(String.valueOf(blue));
+ }
+
+
+ /**
+ * Set the HSB values based on the current RGB values.
+ */
+ protected void updateHSB() {
+ float hsb[] = new float[3];
+ Color.RGBtoHSB(red, green, blue, hsb);
+
+ hue = (int) (hsb[0] * 359.0f);
+ saturation = (int) (hsb[1] * 99.0f);
+ brightness = (int) (hsb[2] * 99.0f);
+
+ hueField.setText(String.valueOf(hue));
+ saturationField.setText(String.valueOf(saturation));
+ brightnessField.setText(String.valueOf(brightness));
+ }
+
+
+ protected void updateHex() {
+ hexField.setText(PApplet.hex(red, 2) +
+ PApplet.hex(green, 2) +
+ PApplet.hex(blue, 2));
+ }
+
+
+ /**
+ * Get the bounded value for a specific range. If the value is outside
+ * the max, you can't edit right away, so just act as if it's already
+ * been bounded and return the bounded value, then fire an event to set
+ * it to the value that was just returned.
+ */
+ protected int bounded(int current, final JTextField field, final int max) {
+ String text = field.getText();
+ if (text.length() == 0) {
+ return 0;
+ }
+ try {
+ int value = Integer.parseInt(text);
+ if (value > max) {
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ field.setText(String.valueOf(max));
+ }
+ });
+ return max;
+ }
+ return value;
+
+ } catch (NumberFormatException e) {
+ return current; // should not be reachable
+ }
+ }
+
+
+ protected Container createColorFields() {
+ Box box = Box.createVerticalBox();
+ box.setAlignmentY(0);
+
+ colorPanel = new JPanel() {
+ public void paintComponent(Graphics g) {
+ g.setColor(new Color(red, green, blue));
+ Dimension size = getSize();
+ g.fillRect(0, 0, size.width, size.height);
+ }
+ };
+ colorPanel.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
+ Dimension dim = new Dimension(60, 40);
+ colorPanel.setMinimumSize(dim);
+ //colorPanel.setMaximumSize(dim);
+ //colorPanel.setPreferredSize(dim);
+ box.add(colorPanel);
+ box.add(Box.createVerticalStrut(10));
+
+ Box row;
+
+ row = Box.createHorizontalBox();
+ row.add(createFixedLabel("H:"));
+ row.add(hueField = new NumberField(4, false));
+ row.add(new JLabel(" \u00B0")); // degree symbol
+ row.add(Box.createHorizontalGlue());
+ box.add(row);
+ box.add(Box.createVerticalStrut(5));
+
+ row = Box.createHorizontalBox();
+ row.add(createFixedLabel("S:"));
+ row.add(saturationField = new NumberField(4, false));
+ row.add(new JLabel(" %"));
+ row.add(Box.createHorizontalGlue());
+ box.add(row);
+ box.add(Box.createVerticalStrut(5));
+
+ row = Box.createHorizontalBox();
+ row.add(createFixedLabel("B:"));
+ row.add(brightnessField = new NumberField(4, false));
+ row.add(new JLabel(" %"));
+ row.add(Box.createHorizontalGlue());
+ box.add(row);
+ box.add(Box.createVerticalStrut(10));
+
+ //
+
+ row = Box.createHorizontalBox();
+ row.add(createFixedLabel("R:"));
+ row.add(redField = new NumberField(4, false));
+ row.add(Box.createHorizontalGlue());
+ box.add(row);
+ box.add(Box.createVerticalStrut(5));
+
+ row = Box.createHorizontalBox();
+ row.add(createFixedLabel("G:"));
+ row.add(greenField = new NumberField(4, false));
+ row.add(Box.createHorizontalGlue());
+ box.add(row);
+ box.add(Box.createVerticalStrut(5));
+
+ row = Box.createHorizontalBox();
+ row.add(createFixedLabel("B:"));
+ row.add(blueField = new NumberField(4, false));
+ row.add(Box.createHorizontalGlue());
+ box.add(row);
+ box.add(Box.createVerticalStrut(10));
+
+ //
+
+ row = Box.createHorizontalBox();
+ row.add(createFixedLabel("#"));
+ row.add(hexField = new NumberField(5, true));
+ row.add(Box.createHorizontalGlue());
+ box.add(row);
+ box.add(Box.createVerticalStrut(10));
+
+ box.add(Box.createVerticalGlue());
+ return box;
+ }
+
+
+ int labelH;
+
+ /**
+ * return a label of a fixed width
+ */
+ protected JLabel createFixedLabel(String title) {
+ JLabel label = new JLabel(title);
+ if (labelH == 0) {
+ labelH = label.getPreferredSize().height;
+ }
+ Dimension dim = new Dimension(20, labelH);
+ label.setPreferredSize(dim);
+ label.setMinimumSize(dim);
+ label.setMaximumSize(dim);
+ return label;
+ }
+
+
+ public class ColorRange extends PApplet {
+
+ static final int WIDE = 256;
+ static final int HIGH = 256;
+
+ int lastX, lastY;
+
+
+ public void setup() {
+ size(WIDE, HIGH, P3D);
+ noLoop();
+
+ colorMode(HSB, 360, 256, 256);
+ noFill();
+ rectMode(CENTER);
+ }
+
+ public void draw() {
+ if ((g == null) || (g.pixels == null)) return;
+ if ((width != WIDE) || (height < HIGH)) {
+ //System.out.println("bad size " + width + " " + height);
+ return;
+ }
+
+ int index = 0;
+ for (int j = 0; j < 256; j++) {
+ for (int i = 0; i < 256; i++) {
+ g.pixels[index++] = color(hue, i, 255 - j);
+ }
+ }
+
+ stroke((brightness > 50) ? 0 : 255);
+ rect(lastX, lastY, 9, 9);
+ }
+
+ public void mousePressed() {
+ updateMouse();
+ }
+
+ public void mouseDragged() {
+ updateMouse();
+ }
+
+ public void updateMouse() {
+ if ((mouseX >= 0) && (mouseX < 256) &&
+ (mouseY >= 0) && (mouseY < 256)) {
+ int nsaturation = (int) (100 * (mouseX / 255.0f));
+ int nbrightness = 100 - ((int) (100 * (mouseY / 255.0f)));
+ saturationField.setText(String.valueOf(nsaturation));
+ brightnessField.setText(String.valueOf(nbrightness));
+
+ lastX = mouseX;
+ lastY = mouseY;
+ }
+ }
+
+ public Dimension getPreferredSize() {
+ //System.out.println("getting pref " + WIDE + " " + HIGH);
+ return new Dimension(WIDE, HIGH);
+ }
+
+ public Dimension getMinimumSize() {
+ //System.out.println("getting min " + WIDE + " " + HIGH);
+ return new Dimension(WIDE, HIGH);
+ }
+
+ public Dimension getMaximumSize() {
+ //System.out.println("getting max " + WIDE + " " + HIGH);
+ return new Dimension(WIDE, HIGH);
+ }
+ }
+
+
+ public class ColorSlider extends PApplet {
+
+ static final int WIDE = 20;
+ static final int HIGH = 256;
+
+ public void setup() {
+ size(WIDE, HIGH, P3D);
+ colorMode(HSB, 255, 100, 100);
+ noLoop();
+ }
+
+ public void draw() {
+ if ((g == null) || (g.pixels == null)) return;
+ if ((width != WIDE) || (height < HIGH)) {
+ //System.out.println("bad size " + width + " " + height);
+ return;
+ }
+
+ int index = 0;
+ int sel = 255 - (int) (255 * (hue / 359f));
+ for (int j = 0; j < 256; j++) {
+ int c = color(255 - j, 100, 100);
+ if (j == sel) c = 0xFF000000;
+ for (int i = 0; i < WIDE; i++) {
+ g.pixels[index++] = c;
+ }
+ }
+ }
+
+ public void mousePressed() {
+ updateMouse();
+ }
+
+ public void mouseDragged() {
+ updateMouse();
+ }
+
+ public void updateMouse() {
+ if ((mouseX >= 0) && (mouseX < 256) &&
+ (mouseY >= 0) && (mouseY < 256)) {
+ int nhue = 359 - (int) (359 * (mouseY / 255.0f));
+ hueField.setText(String.valueOf(nhue));
+ }
+ }
+
+ public Dimension getPreferredSize() {
+ //System.out.println("s getting pref " + WIDE + " " + HIGH);
+ return new Dimension(WIDE, HIGH);
+ }
+
+ public Dimension getMinimumSize() {
+ //System.out.println("s getting min " + WIDE + " " + HIGH);
+ return new Dimension(WIDE, HIGH);
+ }
+
+ public Dimension getMaximumSize() {
+ //System.out.println("s getting max " + WIDE + " " + HIGH);
+ return new Dimension(WIDE, HIGH);
+ }
+ }
+
+
+ /**
+ * Extension of JTextField that only allows numbers
+ */
+ class NumberField extends JTextField {
+
+ public boolean allowHex;
+
+ public NumberField(int cols, boolean allowHex) {
+ super(cols);
+ this.allowHex = allowHex;
+ }
+
+ protected Document createDefaultModel() {
+ return new NumberDocument(this);
+ }
+
+ public Dimension getPreferredSize() {
+ if (!allowHex) {
+ return new Dimension(35, super.getPreferredSize().height);
+ }
+ return super.getPreferredSize();
+ }
+
+ public Dimension getMinimumSize() {
+ return getPreferredSize();
+ }
+
+ public Dimension getMaximumSize() {
+ return getPreferredSize();
+ }
+ }
+
+
+ /**
+ * Document model to go with JTextField that only allows numbers.
+ */
+ class NumberDocument extends PlainDocument {
+
+ NumberField parentField;
+
+ public NumberDocument(NumberField parentField) {
+ this.parentField = parentField;
+ //System.out.println("setting parent to " + parentSelector);
+ }
+
+ public void insertString(int offs, String str, AttributeSet a)
+ throws BadLocationException {
+
+ if (str == null) return;
+
+ char chars[] = str.toCharArray();
+ int charCount = 0;
+ // remove any non-digit chars
+ for (int i = 0; i < chars.length; i++) {
+ boolean ok = Character.isDigit(chars[i]);
+ if (parentField.allowHex) {
+ if ((chars[i] >= 'A') && (chars[i] <= 'F')) ok = true;
+ if ((chars[i] >= 'a') && (chars[i] <= 'f')) ok = true;
+ }
+ if (ok) {
+ if (charCount != i) { // shift if necessary
+ chars[charCount] = chars[i];
+ }
+ charCount++;
+ }
+ }
+ super.insertString(offs, new String(chars, 0, charCount), a);
+ // can't call any sort of methods on the enclosing class here
+ // seems to have something to do with how Document objects are set up
+ }
+ }
+}
diff --git a/app/src/processing/app/tools/CreateFont.java b/app/src/processing/app/tools/CreateFont.java
new file mode 100644
index 000000000..663798985
--- /dev/null
+++ b/app/src/processing/app/tools/CreateFont.java
@@ -0,0 +1,345 @@
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+/*
+ Part of the Processing project - http://processing.org
+
+ Copyright (c) 2004-06 Ben Fry and Casey Reas
+ Copyright (c) 2001-04 Massachusetts Institute of Technology
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+package processing.app.tools;
+
+import processing.app.*;
+import processing.core.*;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.util.*;
+
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.event.*;
+
+
+/**
+ * gui interface to font creation heaven/hell.
+ */
+public class CreateFont extends JFrame implements Tool {
+ Editor editor;
+ //Sketch sketch;
+
+ Dimension windowSize;
+
+ JList fontSelector;
+ //JComboBox styleSelector;
+ JTextField sizeSelector;
+ JCheckBox allBox;
+ JCheckBox smoothBox;
+ JTextArea sample;
+ JButton okButton;
+ JTextField filenameField;
+
+ Hashtable table;
+ boolean smooth = true;
+ boolean all = false;
+
+ Font font;
+
+ String[] list;
+ int selection = -1;
+
+
+ //static {
+ //System.out.println("yep yep yep");
+ //}
+ //static final String styles[] = {
+ //"Plain", "Bold", "Italic", "Bold Italic"
+ //};
+
+
+ public CreateFont() {
+ super("Create Font");
+ }
+
+
+ public String getMenuTitle() {
+ return "Create Font...";
+ }
+
+
+ public void init(Editor editor) {
+ this.editor = editor;
+
+ Container paine = getContentPane();
+ paine.setLayout(new BorderLayout()); //10, 10));
+
+ JPanel pain = new JPanel();
+ pain.setBorder(new EmptyBorder(13, 13, 13, 13));
+ paine.add(pain, BorderLayout.CENTER);
+
+ pain.setLayout(new BoxLayout(pain, BoxLayout.Y_AXIS));
+
+ String labelText =
+ "Use this tool to create bitmap fonts for your program.\n" +
+ "Select a font and size, and click 'OK' to generate the font.\n" +
+ "It will be added to the data folder of the current sketch.";
+
+ JTextArea textarea = new JTextArea(labelText);
+ textarea.setBorder(new EmptyBorder(10, 10, 20, 10));
+ textarea.setBackground(null);
+ textarea.setEditable(false);
+ textarea.setHighlighter(null);
+ textarea.setFont(new Font("Dialog", Font.PLAIN, 12));
+ pain.add(textarea);
+
+ // don't care about families starting with . or #
+ // also ignore dialog, dialoginput, monospaced, serif, sansserif
+
+ // getFontList is deprecated in 1.4, so this has to be used
+ GraphicsEnvironment ge =
+ GraphicsEnvironment.getLocalGraphicsEnvironment();
+
+ Font fonts[] = ge.getAllFonts();
+
+ String flist[] = new String[fonts.length];
+ table = new Hashtable();
+
+ int index = 0;
+ for (int i = 0; i < fonts.length; i++) {
+ //String psname = fonts[i].getPSName();
+ //if (psname == null) System.err.println("ps name is null");
+
+ flist[index++] = fonts[i].getPSName();
+ table.put(fonts[i].getPSName(), fonts[i]);
+ }
+
+ list = new String[index];
+ System.arraycopy(flist, 0, list, 0, index);
+
+ fontSelector = new JList(list);
+ fontSelector.addListSelectionListener(new ListSelectionListener() {
+ public void valueChanged(ListSelectionEvent e) {
+ if (e.getValueIsAdjusting() == false) {
+ selection = fontSelector.getSelectedIndex();
+ okButton.setEnabled(true);
+ update();
+ }
+ }
+ });
+
+ fontSelector.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+ fontSelector.setVisibleRowCount(12);
+ JScrollPane fontScroller = new JScrollPane(fontSelector);
+ pain.add(fontScroller);
+
+ Dimension d1 = new Dimension(13, 13);
+ pain.add(new Box.Filler(d1, d1, d1));
+
+ // see http://rinkworks.com/words/pangrams.shtml
+ sample = new JTextArea("The quick brown fox blah blah.") {
+ // Forsaking monastic tradition, twelve jovial friars gave up their
+ // vocation for a questionable existence on the flying trapeze.
+ public void paintComponent(Graphics g) {
+ //System.out.println("disabling aa");
+ Graphics2D g2 = (Graphics2D) g;
+ g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
+ smooth ?
+ RenderingHints.VALUE_TEXT_ANTIALIAS_ON :
+ RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
+ super.paintComponent(g2);
+ }
+ };
+ // Seems that in some instances, no default font is set
+ // http://dev.processing.org/bugs/show_bug.cgi?id=777
+ sample.setFont(new Font("Dialog", Font.PLAIN, 12));
+
+ pain.add(sample);
+
+ Dimension d2 = new Dimension(6, 6);
+ pain.add(new Box.Filler(d2, d2, d2));
+
+ JPanel panel = new JPanel();
+ panel.add(new JLabel("Size:"));
+ sizeSelector = new JTextField(" 48 ");
+ sizeSelector.getDocument().addDocumentListener(new DocumentListener() {
+ public void insertUpdate(DocumentEvent e) { update(); }
+ public void removeUpdate(DocumentEvent e) { update(); }
+ public void changedUpdate(DocumentEvent e) { }
+ });
+ panel.add(sizeSelector);
+
+ smoothBox = new JCheckBox("Smooth");
+ smoothBox.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ smooth = smoothBox.isSelected();
+ update();
+ }
+ });
+ smoothBox.setSelected(smooth);
+ panel.add(smoothBox);
+
+ allBox = new JCheckBox("All Characters");
+ allBox.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ all = allBox.isSelected();
+ }
+ });
+ allBox.setSelected(all);
+ panel.add(allBox);
+
+ pain.add(panel);
+
+ JPanel filestuff = new JPanel();
+ filestuff.add(new JLabel("Filename:"));
+ filestuff.add(filenameField = new JTextField(20));
+ filestuff.add(new JLabel(".vlw"));
+ pain.add(filestuff);
+
+ JPanel buttons = new JPanel();
+ JButton cancelButton = new JButton("Cancel");
+ cancelButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ setVisible(false);
+ }
+ });
+ okButton = new JButton("OK");
+ okButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ build();
+ }
+ });
+ okButton.setEnabled(false);
+
+ buttons.add(cancelButton);
+ buttons.add(okButton);
+ pain.add(buttons);
+
+ JRootPane root = getRootPane();
+ root.setDefaultButton(okButton);
+ ActionListener disposer = new ActionListener() {
+ public void actionPerformed(ActionEvent actionEvent) {
+ setVisible(false);
+ }
+ };
+ Base.registerWindowCloseKeys(root, disposer);
+ Base.setIcon(this);
+
+ pack();
+
+ // do this after pack so it doesn't affect layout
+ sample.setFont(new Font(list[0], Font.PLAIN, 48));
+
+ fontSelector.setSelectedIndex(0);
+
+ Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
+ windowSize = getSize();
+
+ setLocation((screen.width - windowSize.width) / 2,
+ (screen.height - windowSize.height) / 2);
+ }
+
+
+ public void run() {
+ setVisible(true);
+ }
+
+
+ /**
+ * make the window vertically resizable
+ */
+ public Dimension getMaximumSize() {
+ return new Dimension(windowSize.width, 2000);
+ }
+
+ public Dimension getMinimumSize() {
+ return windowSize;
+ }
+
+
+ /*
+ public void show(File targetFolder) {
+ this.targetFolder = targetFolder;
+ show();
+ }
+ */
+
+
+ public void update() {
+ int fontsize = 0;
+ try {
+ fontsize = Integer.parseInt(sizeSelector.getText().trim());
+ //System.out.println("'" + sizeSelector.getText() + "'");
+ } catch (NumberFormatException e2) { }
+
+ // if a deselect occurred, selection will be -1
+ if ((fontsize > 0) && (fontsize < 256) && (selection != -1)) {
+ //font = new Font(list[selection], Font.PLAIN, fontsize);
+ Font instance = (Font) table.get(list[selection]);
+ font = instance.deriveFont(Font.PLAIN, fontsize);
+ //System.out.println("setting font to " + font);
+ sample.setFont(font);
+
+ String filenameSuggestion = list[selection].replace(' ', '_');
+ filenameSuggestion += "-" + fontsize;
+ filenameField.setText(filenameSuggestion);
+ }
+ }
+
+
+ public void build() {
+ int fontsize = 0;
+ try {
+ fontsize = Integer.parseInt(sizeSelector.getText().trim());
+ } catch (NumberFormatException e) { }
+
+ if (fontsize <= 0) {
+ JOptionPane.showMessageDialog(this, "Bad font size, try again.",
+ "Badness", JOptionPane.WARNING_MESSAGE);
+ return;
+ }
+
+ String filename = filenameField.getText();
+ if (filename.length() == 0) {
+ JOptionPane.showMessageDialog(this, "Enter a file name for the font.",
+ "Lameness", JOptionPane.WARNING_MESSAGE);
+ return;
+ }
+ if (!filename.endsWith(".vlw")) {
+ filename += ".vlw";
+ }
+
+ try {
+ Font instance = (Font) table.get(list[selection]);
+ font = instance.deriveFont(Font.PLAIN, fontsize);
+ PFont f = new PFont(font, smooth, all ? null : PFont.DEFAULT_CHARSET);
+
+ // make sure the 'data' folder exists
+ File folder = editor.getSketch().prepareDataFolder();
+ f.save(new FileOutputStream(new File(folder, filename)));
+
+ } catch (IOException e) {
+ JOptionPane.showMessageDialog(this,
+ "An error occurred while creating font.",
+ "No font for you",
+ JOptionPane.WARNING_MESSAGE);
+ e.printStackTrace();
+ }
+
+ setVisible(false);
+ }
+}
diff --git a/app/src/processing/app/tools/DiscourseFormat.java b/app/src/processing/app/tools/DiscourseFormat.java
new file mode 100644
index 000000000..5de4c0074
--- /dev/null
+++ b/app/src/processing/app/tools/DiscourseFormat.java
@@ -0,0 +1,225 @@
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+/*
+ Part of the Processing project - http://processing.org
+
+ Copyright (c) 2005-06 Ignacio Manuel Gonzalez Moreta.
+ Copyright (c) 2006-08 Ben Fry and Casey Reas
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+package processing.app.tools;
+
+import java.awt.*;
+import java.awt.datatransfer.*;
+import javax.swing.text.Segment;
+
+import processing.app.*;
+import processing.app.syntax.*;
+import processing.core.PApplet;
+
+/**
+ * Format for Discourse Tool
+ *
+ * Original code by owd.
+ * Revised and updated for revision 0108 by Ben Fry (10 March 2006).
+ * This code may later be moved to its own 'Tool' plugin, but is included
+ * with release 0108+ while features for the "Tools" menu are in testing.
+ *
+ * Updated for 0122 to simply copy the code directly to the clipboard,
+ * rather than opening a new window.
+ *
+ * Updated for 0144 to only format the selected lines.
+ *
+ * Notes from the original source:
+ * Discourse.java This is a dirty-mix source.
+ * NOTE that: No macs and no keyboard. Unreliable source.
+ * Only format processing code using fontMetrics.
+ * It works under my windows XP + PentiumIV + Processing 0091.
+ */
+public class DiscourseFormat {
+
+ Editor editor;
+ // JTextArea of the actual Editor
+ JEditTextArea textarea;
+
+
+ /**
+ * Creates a new window with the formated (YaBB tags) sketchcode
+ * from the actual Processing Tab ready to send to the processing discourse
+ * web (copy & paste)
+ */
+ public DiscourseFormat(Editor editor) {
+ this.editor = editor;
+ this.textarea = editor.getTextArea();
+ }
+
+
+ /**
+ * Format and render sketch code.
+ */
+ public void show() {
+ // [code] tag cancels other tags, using [quote]
+ StringBuffer cf = new StringBuffer("[quote]\n");
+
+ int selStart = textarea.getSelectionStart();
+ int selStop = textarea.getSelectionStop();
+
+ int startLine = textarea.getSelectionStartLine();
+ int stopLine = textarea.getSelectionStopLine();
+
+ // If no selection, convert all the lines
+ if (selStart == selStop) {
+ startLine = 0;
+ stopLine = textarea.getLineCount() - 1;
+ } else {
+ // Make sure the selection doesn't end at the beginning of the last line
+ if (textarea.getLineStartOffset(stopLine) == selStop) {
+ stopLine--;
+ }
+ }
+
+ // Read the code line by line
+ for (int i = startLine; i <= stopLine; i++) {
+ appendFormattedLine(cf, i);
+ }
+
+ cf.append("\n[/quote]");
+
+ StringSelection formatted = new StringSelection(cf.toString());
+ Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
+ clipboard.setContents(formatted, new ClipboardOwner() {
+ public void lostOwnership(Clipboard clipboard, Transferable contents) {
+ // i don't care about ownership
+ }
+ });
+
+ editor.statusNotice("Code formatted for processing.org/discourse " +
+ "has been copied to the clipboard.");
+ }
+
+
+ // A terrible headache...
+ public void appendFormattedLine(StringBuffer cf, int line) {
+ Segment segment = new Segment();
+
+ TextAreaPainter painter = textarea.getPainter();
+ TokenMarker tokenMarker = textarea.getTokenMarker();
+
+ // Use painter's cached info for speed
+// FontMetrics fm = painter.getFontMetrics();
+
+ // get line text from parent text area
+ textarea.getLineText(line, segment);
+
+ char[] segmentArray = segment.array;
+ int limit = segment.getEndIndex();
+ int segmentOffset = segment.offset;
+ int segmentCount = segment.count;
+// int width = 0;
+
+ // If syntax coloring is disabled, do simple translation
+ if (tokenMarker == null) {
+ for (int j = 0; j < segmentCount; j++) {
+ char c = segmentArray[j + segmentOffset];
+ cf = cf.append(c);
+// int charWidth;
+// if (c == '\t') {
+// charWidth = (int) painter.nextTabStop(width, j) - width;
+// } else {
+// charWidth = fm.charWidth(c);
+// }
+// width += charWidth;
+ }
+
+ } else {
+ // If syntax coloring is enabled, we have to do this
+ // because tokens can vary in width
+ Token tokens;
+ if ((painter.getCurrentLineIndex() == line) &&
+ (painter.getCurrentLineTokens() != null)) {
+ tokens = painter.getCurrentLineTokens();
+
+ } else {
+ painter.setCurrentLineIndex(line);
+ painter.setCurrentLineTokens(tokenMarker.markTokens(segment, line));
+ tokens = painter.getCurrentLineTokens();
+ }
+
+ int offset = 0;
+// Font defaultFont = painter.getFont();
+ SyntaxStyle[] styles = painter.getStyles();
+
+ for (;;) {
+ byte id = tokens.id;
+ if (id == Token.END) {
+ char c = segmentArray[segmentOffset + offset];
+ if (segmentOffset + offset < limit) {
+ cf.append(c);
+ } else {
+ cf.append('\n');
+ }
+ return; // cf.toString();
+ }
+ if (id == Token.NULL) {
+// fm = painter.getFontMetrics();
+ } else {
+ // Place open tags []
+ cf.append("[color=#");
+ cf.append(PApplet.hex(styles[id].getColor().getRGB() & 0xFFFFFF, 6));
+ cf.append("]");
+
+ if (styles[id].isBold())
+ cf.append("[b]");
+
+// fm = styles[id].getFontMetrics(defaultFont);
+ }
+ int length = tokens.length;
+
+ for (int j = 0; j < length; j++) {
+ char c = segmentArray[segmentOffset + offset + j];
+ if (offset == 0 && c == ' ') {
+ // Works on Safari but not Camino 1.6.3 or Firefox 2.x on OS X.
+ cf.append('\u00A0'); //
+// if ((j % 2) == 1) {
+// cf.append("[b]\u00A0[/b]");
+// } else {
+// cf.append(' ');
+// }
+ } else {
+ cf.append(c);
+ }
+ // Place close tags [/]
+ if (j == (length - 1) && id != Token.NULL && styles[id].isBold())
+ cf.append("[/b]");
+ if (j == (length - 1) && id != Token.NULL)
+ cf.append("[/color]");
+// int charWidth;
+// if (c == '\t') {
+// charWidth = (int) painter
+// .nextTabStop(width, offset + j)
+// - width;
+// } else {
+// charWidth = fm.charWidth(c);
+// }
+// width += charWidth;
+ }
+ offset += length;
+ tokens = tokens.next;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/processing/app/tools/FixEncoding.java b/app/src/processing/app/tools/FixEncoding.java
new file mode 100644
index 000000000..ecdfc6df9
--- /dev/null
+++ b/app/src/processing/app/tools/FixEncoding.java
@@ -0,0 +1,99 @@
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+/*
+ Part of the Processing project - http://processing.org
+
+ Copyright (c) 2008 Ben Fry and Casey Reas
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+package processing.app.tools;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+
+import javax.swing.JOptionPane;
+
+import processing.app.*;
+
+
+public class FixEncoding implements Tool {
+ Editor editor;
+
+
+ public String getMenuTitle() {
+ return "Fix Encoding & Reload";
+ }
+
+
+ public void init(Editor editor) {
+ this.editor = editor;
+ }
+
+
+ public void run() {
+ Sketch sketch = editor.getSketch();
+ //SketchCode code = sketch.current;
+
+ if (sketch.isModified()) {
+ int result =
+ JOptionPane.showConfirmDialog(editor,
+ "Discard all changes and reload sketch?",
+ "Fix Encoding & Reload",
+ JOptionPane.YES_NO_OPTION,
+ JOptionPane.QUESTION_MESSAGE);
+
+ if (result == JOptionPane.NO_OPTION) {
+ return;
+ }
+ }
+ try {
+ for (int i = 0; i < sketch.getCodeCount(); i++) {
+ SketchCode code = sketch.getCode(i);
+ code.setProgram(loadWithLocalEncoding(code.getFile()));
+ code.setModified(true); // yes, because we want them to save this
+ }
+ // Update the currently visible program with its code
+ editor.setText(sketch.getCurrentCode().getProgram());
+
+ } catch (IOException e) {
+ String msg =
+ "An error occurred while trying to fix the file encoding.\n" +
+ "Do not attempt to save this sketch as it may overwrite\n" +
+ "the old version. Use Open to re-open the sketch and try again.\n" +
+ e.getMessage();
+ Base.showWarning("Fix Encoding & Reload", msg, e);
+ }
+ }
+
+
+ protected String loadWithLocalEncoding(File file) throws IOException {
+ // FileReader uses the default encoding, which is what we want.
+ FileReader fr = new FileReader(file);
+ BufferedReader reader = new BufferedReader(fr);
+
+ StringBuffer buffer = new StringBuffer();
+ String line = null;
+ while ((line = reader.readLine()) != null) {
+ buffer.append(line);
+ buffer.append('\n');
+ }
+ reader.close();
+ return buffer.toString();
+ }
+}
\ No newline at end of file
diff --git a/app/src/processing/app/tools/Tool.java b/app/src/processing/app/tools/Tool.java
new file mode 100644
index 000000000..7278452e0
--- /dev/null
+++ b/app/src/processing/app/tools/Tool.java
@@ -0,0 +1,44 @@
+/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+/*
+ Tool - interface implementation for the Processing tools menu
+ Part of the Processing project - http://processing.org
+
+ Copyright (c) 2008 Ben Fry and Casey Reas
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+package processing.app.tools;
+
+import processing.app.Editor;
+
+
+/**
+ * Interface for items to be shown in the Tools menu.
+ */
+public interface Tool extends Runnable {
+
+ public void init(Editor editor);
+
+ public void run();
+
+ // Not doing shortcuts for now, no way to resolve between tools.
+ // Also would need additional modifiers for shift and alt.
+ //public char getShortcutKey();
+
+ public String getMenuTitle();
+}
+
diff --git a/app/src/processing/app/tools/format/src/AutoFormat.java b/app/src/processing/app/tools/format/src/AutoFormat.java
new file mode 100644
index 000000000..e047e9371
--- /dev/null
+++ b/app/src/processing/app/tools/format/src/AutoFormat.java
@@ -0,0 +1,159 @@
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+/*
+ Part of the Processing project - http://processing.org
+
+ Copyright (c) 2006 Ben Fry and Casey Reas
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+package processing.app.tools;
+
+import processing.app.*;
+import processing.core.*;
+
+import java.io.*;
+
+
+/**
+ * Tool for auto-formatting code that interfaces to
+ * Jalopy. This is to replace
+ * the buggy code formatter found in previous releases.
+ */
+public class AutoFormat {
+ Editor editor;
+
+
+ public AutoFormat(Editor editor) {
+ this.editor = editor;
+ }
+
+
+ public void show() {
+ String originalText = editor.textarea.getText();
+ int indentSize = Preferences.getInteger("editor.tabs.size");
+
+ //
+
+ String formattedText = null; //strOut.toString();
+ if (formattedText.equals(originalText)) {
+ editor.message("No changes necessary for Auto Format.");
+
+ } else {
+ // replace with new bootiful text
+ // selectionEnd hopefully at least in the neighborhood
+ editor.setText(formattedText, selectionEnd, selectionEnd);
+ editor.sketch.setModified(true);
+
+ /*
+ // warn user if there are too many parens in either direction
+ if (paren != 0) {
+ editor.error("Warning: Too many " +
+ ((paren < 0) ? "right" : "left") +
+ " parentheses.");
+
+ } else if (c_level != 0) { // check braces only if parens are ok
+ editor.error("Warning: Too many " +
+ ((c_level < 0) ? "right" : "left") +
+ " curly braces.");
+ } else {
+ editor.message("Auto Format finished.");
+ }
+ */
+ }
+ }
+
+
+ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+
+
+ private static class PluginImpl extends AbstractPlugin {
+ JEditStatusBar statusBar;
+ Project project;
+
+
+ /**
+ * Creates a new PluginImpl object.
+ */
+ public PluginImpl()
+ {
+ super(new JEditAppender());
+ }
+
+
+ public Project getActiveProject()
+ {
+ if (this.project == null)
+ {
+ this.project = new JEditProject();
+ }
+
+ return this.project;
+ }
+
+
+ public FileFormat getFileFormat()
+ {
+ // there is a bug(?) in jEdit's text area whereas inserting text with
+ // DOS file format results in displaying EOF characters, so we always
+ // use UNIX format and let jEdit handle the specified file format upon
+ // file saving
+ return FileFormat.UNIX;
+ }
+
+
+ public Frame getMainWindow()
+ {
+ return jEdit.getActiveView();
+ }
+
+
+ public StatusBar getStatusBar()
+ {
+ return this.statusBar;
+ }
+
+
+ public void afterEnd()
+ {
+ super.afterEnd();
+ MessageView.getInstance().update();
+ }
+
+
+ /**
+ * Formats the currently active buffer.
+ */
+ public void formatActive()
+ {
+ // only perform the action if the current Buffer contains
+ // a Java source file
+ //if (isJava(jEdit.getActiveView().getBuffer()))
+ //{
+ performAction(Action.FORMAT_ACTIVE);
+ //}
+ }
+
+
+ /**
+ * Formats the currently open buffers.
+ */
+ public void formatOpen()
+ {
+ performAction(Action.FORMAT_OPEN);
+ }
+ }
+}
diff --git a/app/src/processing/app/tools/format/tool/jalopy.jar b/app/src/processing/app/tools/format/tool/jalopy.jar
new file mode 100644
index 000000000..fe51ce230
Binary files /dev/null and b/app/src/processing/app/tools/format/tool/jalopy.jar differ
diff --git a/app/src/processing/app/tools/format/tool/log4j.jar b/app/src/processing/app/tools/format/tool/log4j.jar
new file mode 100644
index 000000000..493a3ccc1
Binary files /dev/null and b/app/src/processing/app/tools/format/tool/log4j.jar differ
diff --git a/app/src/processing/app/windows/Advapi32.java b/app/src/processing/app/windows/Advapi32.java
new file mode 100644
index 000000000..0534d6b21
--- /dev/null
+++ b/app/src/processing/app/windows/Advapi32.java
@@ -0,0 +1,335 @@
+package processing.app.windows;
+
+/*
+ * Advapi32.java
+ *
+ * Created on 6. August 2007, 11:24
+ *
+ * To change this template, choose Tools | Template Manager
+ * and open the template in the editor.
+ */
+
+import com.sun.jna.*;
+import com.sun.jna.ptr.*;
+import com.sun.jna.win32.*;
+
+/**
+ *
+ * @author TB
+ */
+public interface Advapi32 extends StdCallLibrary {
+ Advapi32 INSTANCE = (Advapi32) Native.loadLibrary("Advapi32", Advapi32.class, Options.UNICODE_OPTIONS);
+
+/*
+BOOL WINAPI LookupAccountName(
+ LPCTSTR lpSystemName,
+ LPCTSTR lpAccountName,
+ PSID Sid,
+ LPDWORD cbSid,
+ LPTSTR ReferencedDomainName,
+ LPDWORD cchReferencedDomainName,
+ PSID_NAME_USE peUse
+);*/
+ public boolean LookupAccountName(String lpSystemName, String lpAccountName,
+ byte[] Sid, IntByReference cbSid, char[] ReferencedDomainName,
+ IntByReference cchReferencedDomainName, PointerByReference peUse);
+
+/*
+BOOL WINAPI LookupAccountSid(
+ LPCTSTR lpSystemName,
+ PSID lpSid,
+ LPTSTR lpName,
+ LPDWORD cchName,
+ LPTSTR lpReferencedDomainName,
+ LPDWORD cchReferencedDomainName,
+ PSID_NAME_USE peUse
+);*/
+ public boolean LookupAccountSid(String lpSystemName, byte[] Sid,
+ char[] lpName, IntByReference cchName, char[] ReferencedDomainName,
+ IntByReference cchReferencedDomainName, PointerByReference peUse);
+
+/*
+BOOL ConvertSidToStringSid(
+ PSID Sid,
+ LPTSTR* StringSid
+);*/
+ public boolean ConvertSidToStringSid(byte[] Sid, PointerByReference StringSid);
+
+/*
+BOOL WINAPI ConvertStringSidToSid(
+ LPCTSTR StringSid,
+ PSID* Sid
+);*/
+ public boolean ConvertStringSidToSid(String StringSid, PointerByReference Sid);
+
+/*
+SC_HANDLE WINAPI OpenSCManager(
+ LPCTSTR lpMachineName,
+ LPCTSTR lpDatabaseName,
+ DWORD dwDesiredAccess
+);*/
+ public Pointer OpenSCManager(String lpMachineName, WString lpDatabaseName, int dwDesiredAccess);
+
+/*
+BOOL WINAPI CloseServiceHandle(
+ SC_HANDLE hSCObject
+);*/
+ public boolean CloseServiceHandle(Pointer hSCObject);
+
+/*
+SC_HANDLE WINAPI OpenService(
+ SC_HANDLE hSCManager,
+ LPCTSTR lpServiceName,
+ DWORD dwDesiredAccess
+);*/
+ public Pointer OpenService(Pointer hSCManager, String lpServiceName, int dwDesiredAccess);
+
+/*
+BOOL WINAPI StartService(
+ SC_HANDLE hService,
+ DWORD dwNumServiceArgs,
+ LPCTSTR* lpServiceArgVectors
+);*/
+ public boolean StartService(Pointer hService, int dwNumServiceArgs, char[] lpServiceArgVectors);
+
+/*
+BOOL WINAPI ControlService(
+ SC_HANDLE hService,
+ DWORD dwControl,
+ LPSERVICE_STATUS lpServiceStatus
+);*/
+ public boolean ControlService(Pointer hService, int dwControl, SERVICE_STATUS lpServiceStatus);
+
+/*
+BOOL WINAPI StartServiceCtrlDispatcher(
+ const SERVICE_TABLE_ENTRY* lpServiceTable
+);*/
+ public boolean StartServiceCtrlDispatcher(Structure[] lpServiceTable);
+
+/*
+SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandler(
+ LPCTSTR lpServiceName,
+ LPHANDLER_FUNCTION lpHandlerProc
+);*/
+ public Pointer RegisterServiceCtrlHandler(String lpServiceName, Handler lpHandlerProc);
+
+/*
+SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerEx(
+ LPCTSTR lpServiceName,
+ LPHANDLER_FUNCTION_EX lpHandlerProc,
+ LPVOID lpContext
+);*/
+ public Pointer RegisterServiceCtrlHandlerEx(String lpServiceName, HandlerEx lpHandlerProc, Pointer lpContext);
+
+/*
+BOOL WINAPI SetServiceStatus(
+ SERVICE_STATUS_HANDLE hServiceStatus,
+ LPSERVICE_STATUS lpServiceStatus
+);*/
+ public boolean SetServiceStatus(Pointer hServiceStatus, SERVICE_STATUS lpServiceStatus);
+
+/*
+SC_HANDLE WINAPI CreateService(
+ SC_HANDLE hSCManager,
+ LPCTSTR lpServiceName,
+ LPCTSTR lpDisplayName,
+ DWORD dwDesiredAccess,
+ DWORD dwServiceType,
+ DWORD dwStartType,
+ DWORD dwErrorControl,
+ LPCTSTR lpBinaryPathName,
+ LPCTSTR lpLoadOrderGroup,
+ LPDWORD lpdwTagId,
+ LPCTSTR lpDependencies,
+ LPCTSTR lpServiceStartName,
+ LPCTSTR lpPassword
+);*/
+ public Pointer CreateService(Pointer hSCManager, String lpServiceName, String lpDisplayName,
+ int dwDesiredAccess, int dwServiceType, int dwStartType, int dwErrorControl,
+ String lpBinaryPathName, String lpLoadOrderGroup, IntByReference lpdwTagId,
+ String lpDependencies, String lpServiceStartName, String lpPassword);
+
+/*
+BOOL WINAPI DeleteService(
+ SC_HANDLE hService
+);*/
+ public boolean DeleteService(Pointer hService);
+
+/*
+BOOL WINAPI ChangeServiceConfig2(
+ SC_HANDLE hService,
+ DWORD dwInfoLevel,
+ LPVOID lpInfo
+);*/
+ public boolean ChangeServiceConfig2(Pointer hService, int dwInfoLevel, ChangeServiceConfig2Info lpInfo);
+
+/*
+LONG WINAPI RegOpenKeyEx(
+ HKEY hKey,
+ LPCTSTR lpSubKey,
+ DWORD ulOptions,
+ REGSAM samDesired,
+ PHKEY phkResult
+);*/
+ public int RegOpenKeyEx(int hKey, String lpSubKey, int ulOptions, int samDesired, IntByReference phkResult);
+
+/*
+LONG WINAPI RegQueryValueEx(
+ HKEY hKey,
+ LPCTSTR lpValueName,
+ LPDWORD lpReserved,
+ LPDWORD lpType,
+ LPBYTE lpData,
+ LPDWORD lpcbData
+);*/
+ public int RegQueryValueEx(int hKey, String lpValueName, IntByReference lpReserved, IntByReference lpType, byte[] lpData, IntByReference lpcbData);
+
+/*
+LONG WINAPI RegCloseKey(
+ HKEY hKey
+);*/
+ public int RegCloseKey(int hKey);
+
+/*
+LONG WINAPI RegDeleteValue(
+ HKEY hKey,
+ LPCTSTR lpValueName
+);*/
+ public int RegDeleteValue(int hKey, String lpValueName);
+
+/*
+LONG WINAPI RegSetValueEx(
+ HKEY hKey,
+ LPCTSTR lpValueName,
+ DWORD Reserved,
+ DWORD dwType,
+ const BYTE* lpData,
+ DWORD cbData
+);*/
+ public int RegSetValueEx(int hKey, String lpValueName, int Reserved, int dwType, byte[] lpData, int cbData);
+
+/*
+LONG WINAPI RegCreateKeyEx(
+ HKEY hKey,
+ LPCTSTR lpSubKey,
+ DWORD Reserved,
+ LPTSTR lpClass,
+ DWORD dwOptions,
+ REGSAM samDesired,
+ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
+ PHKEY phkResult,
+ LPDWORD lpdwDisposition
+);*/
+ public int RegCreateKeyEx(int hKey, String lpSubKey, int Reserved, String lpClass, int dwOptions,
+ int samDesired, WINBASE.SECURITY_ATTRIBUTES lpSecurityAttributes, IntByReference phkResult,
+ IntByReference lpdwDisposition);
+
+/*
+LONG WINAPI RegDeleteKey(
+ HKEY hKey,
+ LPCTSTR lpSubKey
+);*/
+ public int RegDeleteKey(int hKey, String name);
+
+/*
+LONG WINAPI RegEnumKeyEx(
+ HKEY hKey,
+ DWORD dwIndex,
+ LPTSTR lpName,
+ LPDWORD lpcName,
+ LPDWORD lpReserved,
+ LPTSTR lpClass,
+ LPDWORD lpcClass,
+ PFILETIME lpftLastWriteTime
+);*/
+ public int RegEnumKeyEx(int hKey, int dwIndex, char[] lpName, IntByReference lpcName, IntByReference reserved,
+ char[] lpClass, IntByReference lpcClass, WINBASE.FILETIME lpftLastWriteTime);
+
+/*
+LONG WINAPI RegEnumValue(
+ HKEY hKey,
+ DWORD dwIndex,
+ LPTSTR lpValueName,
+ LPDWORD lpcchValueName,
+ LPDWORD lpReserved,
+ LPDWORD lpType,
+ LPBYTE lpData,
+ LPDWORD lpcbData
+);*/
+ public int RegEnumValue(int hKey, int dwIndex, char[] lpValueName, IntByReference lpcchValueName, IntByReference reserved,
+ IntByReference lpType, byte[] lpData, IntByReference lpcbData);
+
+ interface SERVICE_MAIN_FUNCTION extends StdCallCallback {
+ /*
+ VOID WINAPI ServiceMain(
+ DWORD dwArgc,
+ LPTSTR* lpszArgv
+ );*/
+ public void callback(int dwArgc, Pointer lpszArgv);
+ }
+
+ interface Handler extends StdCallCallback {
+ /*
+ VOID WINAPI Handler(
+ DWORD fdwControl
+ );*/
+ public void callback(int fdwControl);
+ }
+
+ interface HandlerEx extends StdCallCallback {
+ /*
+ DWORD WINAPI HandlerEx(
+ DWORD dwControl,
+ DWORD dwEventType,
+ LPVOID lpEventData,
+ LPVOID lpContext
+ );*/
+ public void callback(int dwControl, int dwEventType, Pointer lpEventData, Pointer lpContext);
+ }
+
+/*
+typedef struct _SERVICE_STATUS {
+ DWORD dwServiceType;
+ DWORD dwCurrentState;
+ DWORD dwControlsAccepted;
+ DWORD dwWin32ExitCode;
+ DWORD dwServiceSpecificExitCode;
+ DWORD dwCheckPoint;
+ DWORD dwWaitHint;
+} SERVICE_STATUS,
+ *LPSERVICE_STATUS;*/
+ public static class SERVICE_STATUS extends Structure {
+ public int dwServiceType;
+ public int dwCurrentState;
+ public int dwControlsAccepted;
+ public int dwWin32ExitCode;
+ public int dwServiceSpecificExitCode;
+ public int dwCheckPoint;
+ public int dwWaitHint;
+ }
+
+/*
+typedef struct _SERVICE_TABLE_ENTRY {
+ LPTSTR lpServiceName;
+ LPSERVICE_MAIN_FUNCTION lpServiceProc;
+} SERVICE_TABLE_ENTRY,
+ *LPSERVICE_TABLE_ENTRY;*/
+ public static class SERVICE_TABLE_ENTRY extends Structure {
+ public String lpServiceName;
+ public SERVICE_MAIN_FUNCTION lpServiceProc;
+ }
+
+ public static class ChangeServiceConfig2Info extends Structure {
+ }
+
+/*
+ typedef struct _SERVICE_DESCRIPTION {
+ LPTSTR lpDescription;
+} SERVICE_DESCRIPTION,
+ *LPSERVICE_DESCRIPTION;*/
+ public static class SERVICE_DESCRIPTION extends ChangeServiceConfig2Info {
+ public String lpDescription;
+ }
+}
+
+
diff --git a/app/src/processing/app/windows/Options.java b/app/src/processing/app/windows/Options.java
new file mode 100644
index 000000000..f5cff2888
--- /dev/null
+++ b/app/src/processing/app/windows/Options.java
@@ -0,0 +1,27 @@
+/*
+ * Options.java
+ *
+ * Created on 8. August 2007, 17:07
+ *
+ * To change this template, choose Tools | Template Manager
+ * and open the template in the editor.
+ */
+
+package processing.app.windows;
+
+import static com.sun.jna.Library.*;
+import com.sun.jna.win32.*;
+import java.util.*;
+
+/**
+ *
+ * @author TB
+ */
+public interface Options {
+ Map UNICODE_OPTIONS = new HashMap() {
+ {
+ put(OPTION_TYPE_MAPPER, W32APITypeMapper.UNICODE);
+ put(OPTION_FUNCTION_MAPPER, W32APIFunctionMapper.UNICODE);
+ }
+ };
+}
diff --git a/app/src/processing/app/windows/Platform.java b/app/src/processing/app/windows/Platform.java
new file mode 100644
index 000000000..278244447
--- /dev/null
+++ b/app/src/processing/app/windows/Platform.java
@@ -0,0 +1,268 @@
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+/*
+ Part of the Processing project - http://processing.org
+
+ Copyright (c) 2008 Ben Fry and Casey Reas
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+package processing.app.windows;
+
+import java.io.File;
+import java.io.UnsupportedEncodingException;
+
+import processing.app.Base;
+import processing.app.Preferences;
+import processing.app.windows.Registry.REGISTRY_ROOT_KEY;
+import processing.core.PApplet;
+
+
+// http://developer.apple.com/documentation/QuickTime/Conceptual/QT7Win_Update_Guide/Chapter03/chapter_3_section_1.html
+// HKEY_LOCAL_MACHINE\SOFTWARE\Apple Computer, Inc.\QuickTime\QTSysDir
+
+// HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Development Kit\CurrentVersion -> 1.6 (String)
+// HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Development Kit\CurrentVersion\1.6\JavaHome -> c:\jdk-1.6.0_05
+
+public class Platform extends processing.app.Platform {
+
+ static final String openCommand =
+ System.getProperty("user.dir").replace('/', '\\') +
+ "\\processing.exe \"%1\"";
+ static final String DOC = "Processing.Document";
+
+ public void init(Base base) {
+ super.init(base);
+
+ checkAssociations();
+ checkQuickTime();
+ checkPath();
+ }
+
+
+ /**
+ * Make sure that .pde files are associated with processing.exe.
+ */
+ protected void checkAssociations() {
+ try {
+ String knownCommand =
+ Registry.getStringValue(REGISTRY_ROOT_KEY.CLASSES_ROOT,
+ DOC + "\\shell\\open\\command", "");
+ if (knownCommand == null) {
+ if (Preferences.getBoolean("platform.auto_file_type_associations")) {
+ setAssociations();
+ }
+
+ } else if (!knownCommand.equals(openCommand)) {
+ // If the value is set differently, just change the registry setting.
+ if (Preferences.getBoolean("platform.auto_file_type_associations")) {
+ setAssociations();
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ /**
+ * Associate .pde files with this version of Processing.
+ */
+ protected void setAssociations() throws UnsupportedEncodingException {
+ if (Registry.createKey(REGISTRY_ROOT_KEY.CLASSES_ROOT,
+ "", ".pde") &&
+ Registry.setStringValue(REGISTRY_ROOT_KEY.CLASSES_ROOT,
+ ".pde", "", DOC) &&
+
+ Registry.createKey(REGISTRY_ROOT_KEY.CLASSES_ROOT, "", DOC) &&
+ Registry.setStringValue(REGISTRY_ROOT_KEY.CLASSES_ROOT, DOC, "",
+ "Processing Source Code") &&
+
+ Registry.createKey(REGISTRY_ROOT_KEY.CLASSES_ROOT,
+ DOC, "shell") &&
+ Registry.createKey(REGISTRY_ROOT_KEY.CLASSES_ROOT,
+ DOC + "\\shell", "open") &&
+ Registry.createKey(REGISTRY_ROOT_KEY.CLASSES_ROOT,
+ DOC + "\\shell\\open", "command") &&
+ Registry.setStringValue(REGISTRY_ROOT_KEY.CLASSES_ROOT,
+ DOC + "\\shell\\open\\command", "",
+ openCommand)) {
+ // everything ok
+ // hooray!
+
+ } else {
+ Preferences.setBoolean("platform.auto_file_type_associations", false);
+ }
+ }
+
+
+ /**
+ * Find QuickTime for Java installation.
+ */
+ protected void checkQuickTime() {
+ try {
+ String qtsystemPath =
+ Registry.getStringValue(REGISTRY_ROOT_KEY.LOCAL_MACHINE,
+ "Software\\Apple Computer, Inc.\\QuickTime",
+ "QTSysDir");
+ // Could show a warning message here if QT not installed, but that
+ // would annoy people who don't want anything to do with QuickTime.
+ if (qtsystemPath != null) {
+ File qtjavaZip = new File(qtsystemPath, "QTJava.zip");
+ if (qtjavaZip.exists()) {
+ String qtjavaZipPath = qtjavaZip.getAbsolutePath();
+ String cp = System.getProperty("java.class.path");
+ System.setProperty("java.class.path",
+ cp + File.pathSeparator + qtjavaZipPath);
+ }
+ }
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ /**
+ * Remove extra quotes, slashes, and garbage from the Windows PATH.
+ */
+ protected void checkPath() {
+ String path = System.getProperty("java.library.path");
+ String[] pieces = PApplet.split(path, File.pathSeparatorChar);
+ String[] legit = new String[pieces.length];
+ int legitCount = 0;
+ for (String item : pieces) {
+ if (item.startsWith("\"")) {
+ item = item.substring(1);
+ }
+ if (item.endsWith("\"")) {
+ item = item.substring(0, item.length() - 1);
+ }
+ if (item.endsWith(File.separator)) {
+ item = item.substring(0, item.length() - File.separator.length());
+ }
+ File directory = new File(item);
+ if (!directory.exists()) {
+ continue;
+ }
+ if (item.trim().length() == 0) {
+ continue;
+ }
+ legit[legitCount++] = item;
+ }
+ legit = PApplet.subset(legit, 0, legitCount);
+ String newPath = PApplet.join(legit, File.pathSeparator);
+ if (!newPath.equals(path)) {
+ System.setProperty("java.library.path", newPath);
+ }
+ }
+
+
+ // looking for Documents and Settings/blah/Application Data/Processing
+ public File getSettingsFolder() throws Exception {
+ // HKEY_CURRENT_USER\Software\Microsoft
+ // \Windows\CurrentVersion\Explorer\Shell Folders
+ // Value Name: AppData
+ // Value Type: REG_SZ
+ // Value Data: path
+
+ String keyPath =
+ "Software\\Microsoft\\Windows\\CurrentVersion" +
+ "\\Explorer\\Shell Folders";
+ String appDataPath =
+ Registry.getStringValue(REGISTRY_ROOT_KEY.CURRENT_USER, keyPath, "AppData");
+
+ File dataFolder = new File(appDataPath, "Processing");
+ return dataFolder;
+ }
+
+
+ // looking for Documents and Settings/blah/My Documents/Processing
+ // (though using a reg key since it's different on other platforms)
+ public File getDefaultSketchbookFolder() throws Exception {
+
+ // http://support.microsoft.com/?kbid=221837&sd=RMVP
+ // http://support.microsoft.com/kb/242557/en-us
+
+ // The path to the My Documents folder is stored in the following
+ // registry key, where path is the complete path to your storage location
+
+ // HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders
+ // Value Name: Personal
+ // Value Type: REG_SZ
+ // Value Data: path
+
+ // in some instances, this may be overridden by a policy, in which case check:
+ // HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders
+
+ String keyPath =
+ "Software\\Microsoft\\Windows\\CurrentVersion" +
+ "\\Explorer\\Shell Folders";
+ String personalPath =
+ Registry.getStringValue(REGISTRY_ROOT_KEY.CURRENT_USER, keyPath, "Personal");
+
+ return new File(personalPath, "Processing");
+ }
+
+
+ public void openURL(String url) throws Exception {
+ // this is not guaranteed to work, because who knows if the
+ // path will always be c:\progra~1 et al. also if the user has
+ // a different browser set as their default (which would
+ // include me) it'd be annoying to be dropped into ie.
+ //Runtime.getRuntime().exec("c:\\progra~1\\intern~1\\iexplore "
+ // + currentDir
+
+ // the following uses a shell execute to launch the .html file
+ // note that under cygwin, the .html files have to be chmodded +x
+ // after they're unpacked from the zip file. i don't know why,
+ // and don't understand what this does in terms of windows
+ // permissions. without the chmod, the command prompt says
+ // "Access is denied" in both cygwin and the "dos" prompt.
+ //Runtime.getRuntime().exec("cmd /c " + currentDir + "\\reference\\" +
+ // referenceFile + ".html");
+ if (url.startsWith("http://")) {
+ // open dos prompt, give it 'start' command, which will
+ // open the url properly. start by itself won't work since
+ // it appears to need cmd
+ Runtime.getRuntime().exec("cmd /c start " + url);
+ } else {
+ // just launching the .html file via the shell works
+ // but make sure to chmod +x the .html files first
+ // also place quotes around it in case there's a space
+ // in the user.dir part of the url
+ Runtime.getRuntime().exec("cmd /c \"" + url + "\"");
+ }
+ }
+
+
+ public boolean openFolderAvailable() {
+ return true;
+ }
+
+
+ public void openFolder(File file) throws Exception {
+ String folder = file.getAbsolutePath();
+
+ // doesn't work
+ //Runtime.getRuntime().exec("cmd /c \"" + folder + "\"");
+
+ // works fine on winxp, prolly win2k as well
+ Runtime.getRuntime().exec("explorer \"" + folder + "\"");
+
+ // not tested
+ //Runtime.getRuntime().exec("start explorer \"" + folder + "\"");
+ }
+}
diff --git a/app/src/processing/app/windows/Registry.java b/app/src/processing/app/windows/Registry.java
new file mode 100644
index 000000000..71fa5eebe
--- /dev/null
+++ b/app/src/processing/app/windows/Registry.java
@@ -0,0 +1,456 @@
+package processing.app.windows;
+
+import java.io.UnsupportedEncodingException;
+import java.util.HashMap;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+import com.sun.jna.ptr.IntByReference;
+
+/**
+ * Methods for accessing the Windows Registry. Only String and DWORD values supported at the moment.
+ */
+public class Registry {
+ public static enum REGISTRY_ROOT_KEY{CLASSES_ROOT, CURRENT_USER, LOCAL_MACHINE, USERS};
+ private final static HashMap rootKeyMap = new HashMap();
+
+ static {
+ rootKeyMap.put(REGISTRY_ROOT_KEY.CLASSES_ROOT, WINREG.HKEY_CLASSES_ROOT);
+ rootKeyMap.put(REGISTRY_ROOT_KEY.CURRENT_USER, WINREG.HKEY_CURRENT_USER);
+ rootKeyMap.put(REGISTRY_ROOT_KEY.LOCAL_MACHINE, WINREG.HKEY_LOCAL_MACHINE);
+ rootKeyMap.put(REGISTRY_ROOT_KEY.USERS, WINREG.HKEY_USERS);
+ }
+
+ /**
+ * Testing.
+ *
+ * @param args arguments
+ * @throws java.lang.Exception on error
+ */
+ public static void main(String[] args) throws Exception {
+ }
+
+ /**
+ * Gets one of the root keys.
+ *
+ * @param key key type
+ * @return root key
+ */
+ private static int getRegistryRootKey(REGISTRY_ROOT_KEY key) {
+ Advapi32 advapi32;
+ IntByReference pHandle;
+ int handle = 0;
+
+ advapi32 = Advapi32.INSTANCE;
+ pHandle = new IntByReference();
+
+ if(advapi32.RegOpenKeyEx(rootKeyMap.get(key), null, 0, 0, pHandle) == WINERROR.ERROR_SUCCESS) {
+ handle = pHandle.getValue();
+ }
+ return(handle);
+ }
+
+ /**
+ * Opens a key.
+ *
+ * @param rootKey root key
+ * @param subKeyName name of the key
+ * @param access access mode
+ * @return handle to the key or 0
+ */
+ private static int openKey(REGISTRY_ROOT_KEY rootKey, String subKeyName, int access) {
+ Advapi32 advapi32;
+ IntByReference pHandle;
+ int rootKeyHandle;
+
+ advapi32 = Advapi32.INSTANCE;
+ rootKeyHandle = getRegistryRootKey(rootKey);
+ pHandle = new IntByReference();
+
+ if(advapi32.RegOpenKeyEx(rootKeyHandle, subKeyName, 0, access, pHandle) == WINERROR.ERROR_SUCCESS) {
+ return(pHandle.getValue());
+
+ } else {
+ return(0);
+ }
+ }
+
+ /**
+ * Converts a Windows buffer to a Java String.
+ *
+ * @param buf buffer
+ * @throws java.io.UnsupportedEncodingException on error
+ * @return String
+ */
+ private static String convertBufferToString(byte[] buf) throws UnsupportedEncodingException {
+ return(new String(buf, 0, buf.length - 2, "UTF-16LE"));
+ }
+
+ /**
+ * Converts a Windows buffer to an int.
+ *
+ * @param buf buffer
+ * @return int
+ */
+ private static int convertBufferToInt(byte[] buf) {
+ return(((int)(buf[0] & 0xff)) + (((int)(buf[1] & 0xff)) << 8) + (((int)(buf[2] & 0xff)) << 16) + (((int)(buf[3] & 0xff)) << 24));
+ }
+
+ /**
+ * Read a String value.
+ *
+ * @param rootKey root key
+ * @param subKeyName key name
+ * @param name value name
+ * @throws java.io.UnsupportedEncodingException on error
+ * @return String or null
+ */
+ public static String getStringValue(REGISTRY_ROOT_KEY rootKey, String subKeyName, String name) throws UnsupportedEncodingException {
+ Advapi32 advapi32;
+ IntByReference pType, lpcbData;
+ byte[] lpData = new byte[1];
+ int handle = 0;
+ String ret = null;
+
+ advapi32 = Advapi32.INSTANCE;
+ pType = new IntByReference();
+ lpcbData = new IntByReference();
+ handle = openKey(rootKey, subKeyName, WINNT.KEY_READ);
+
+ if(handle != 0) {
+
+ if(advapi32.RegQueryValueEx(handle, name, null, pType, lpData, lpcbData) == WINERROR.ERROR_MORE_DATA) {
+ lpData = new byte[lpcbData.getValue()];
+
+ if(advapi32.RegQueryValueEx(handle, name, null, pType, lpData, lpcbData) == WINERROR.ERROR_SUCCESS) {
+ ret = convertBufferToString(lpData);
+ }
+ }
+ advapi32.RegCloseKey(handle);
+ }
+ return(ret);
+ }
+
+ /**
+ * Read an int value.
+ *
+ *
+ * @return int or 0
+ * @param rootKey root key
+ * @param subKeyName key name
+ * @param name value name
+ */
+ public static int getIntValue(REGISTRY_ROOT_KEY rootKey, String subKeyName, String name) {
+ Advapi32 advapi32;
+ IntByReference pType, lpcbData;
+ byte[] lpData = new byte[1];
+ int handle = 0;
+ int ret = 0;
+
+ advapi32 = Advapi32.INSTANCE;
+ pType = new IntByReference();
+ lpcbData = new IntByReference();
+ handle = openKey(rootKey, subKeyName, WINNT.KEY_READ);
+
+ if(handle != 0) {
+
+ if(advapi32.RegQueryValueEx(handle, name, null, pType, lpData, lpcbData) == WINERROR.ERROR_MORE_DATA) {
+ lpData = new byte[lpcbData.getValue()];
+
+ if(advapi32.RegQueryValueEx(handle, name, null, pType, lpData, lpcbData) == WINERROR.ERROR_SUCCESS) {
+ ret = convertBufferToInt(lpData);
+ }
+ }
+ advapi32.RegCloseKey(handle);
+ }
+ return(ret);
+ }
+
+ /**
+ * Delete a value.
+ *
+ * @param rootKey root key
+ * @param subKeyName key name
+ * @param name value name
+ * @return true on success
+ */
+ public static boolean deleteValue(REGISTRY_ROOT_KEY rootKey, String subKeyName, String name) {
+ Advapi32 advapi32;
+ int handle;
+ boolean ret = true;
+
+ advapi32 = Advapi32.INSTANCE;
+
+ handle = openKey(rootKey, subKeyName, WINNT.KEY_READ | WINNT.KEY_WRITE);
+
+ if(handle != 0) {
+ if(advapi32.RegDeleteValue(handle, name) == WINERROR.ERROR_SUCCESS) {
+ ret = true;
+ }
+ advapi32.RegCloseKey(handle);
+ }
+ return(ret);
+ }
+
+ /**
+ * Writes a String value.
+ *
+ * @param rootKey root key
+ * @param subKeyName key name
+ * @param name value name
+ * @param value value
+ * @throws java.io.UnsupportedEncodingException on error
+ * @return true on success
+ */
+ public static boolean setStringValue(REGISTRY_ROOT_KEY rootKey, String subKeyName, String name, String value) throws UnsupportedEncodingException {
+ Advapi32 advapi32;
+ int handle;
+ byte[] data;
+ boolean ret = false;
+
+ // appears to be Java 1.6 syntax, removing [fry]
+ //data = Arrays.copyOf(value.getBytes("UTF-16LE"), value.length() * 2 + 2);
+ data = new byte[value.length() * 2 + 2];
+ byte[] src = value.getBytes("UTF-16LE");
+ System.arraycopy(src, 0, data, 0, src.length);
+
+ advapi32 = Advapi32.INSTANCE;
+ handle = openKey(rootKey, subKeyName, WINNT.KEY_READ | WINNT.KEY_WRITE);
+
+ if(handle != 0) {
+ if(advapi32.RegSetValueEx(handle, name, 0, WINNT.REG_SZ, data, data.length) == WINERROR.ERROR_SUCCESS) {
+ ret = true;
+ }
+ advapi32.RegCloseKey(handle);
+ }
+ return(ret);
+ }
+
+ /**
+ * Writes an int value.
+ *
+ *
+ * @return true on success
+ * @param rootKey root key
+ * @param subKeyName key name
+ * @param name value name
+ * @param value value
+ */
+ public static boolean setIntValue(REGISTRY_ROOT_KEY rootKey, String subKeyName, String name, int value) {
+ Advapi32 advapi32;
+ int handle;
+ byte[] data;
+ boolean ret = false;
+
+ data = new byte[4];
+ data[0] = (byte)(value & 0xff);
+ data[1] = (byte)((value >> 8) & 0xff);
+ data[2] = (byte)((value >> 16) & 0xff);
+ data[3] = (byte)((value >> 24) & 0xff);
+ advapi32 = Advapi32.INSTANCE;
+ handle = openKey(rootKey, subKeyName, WINNT.KEY_READ | WINNT.KEY_WRITE);
+
+ if(handle != 0) {
+
+ if(advapi32.RegSetValueEx(handle, name, 0, WINNT.REG_DWORD, data, data.length) == WINERROR.ERROR_SUCCESS) {
+ ret = true;
+ }
+ advapi32.RegCloseKey(handle);
+ }
+ return(ret);
+ }
+
+ /**
+ * Check for existence of a value.
+ *
+ * @param rootKey root key
+ * @param subKeyName key name
+ * @param name value name
+ * @return true if exists
+ */
+ public static boolean valueExists(REGISTRY_ROOT_KEY rootKey, String subKeyName, String name) {
+ Advapi32 advapi32;
+ IntByReference pType, lpcbData;
+ byte[] lpData = new byte[1];
+ int handle = 0;
+ boolean ret = false;
+
+ advapi32 = Advapi32.INSTANCE;
+ pType = new IntByReference();
+ lpcbData = new IntByReference();
+ handle = openKey(rootKey, subKeyName, WINNT.KEY_READ);
+
+ if(handle != 0) {
+
+ if(advapi32.RegQueryValueEx(handle, name, null, pType, lpData, lpcbData) != WINERROR.ERROR_FILE_NOT_FOUND) {
+ ret = true;
+
+ } else {
+ ret = false;
+ }
+ advapi32.RegCloseKey(handle);
+ }
+ return(ret);
+ }
+
+ /**
+ * Create a new key.
+ *
+ * @param rootKey root key
+ * @param parent name of parent key
+ * @param name key name
+ * @return true on success
+ */
+ public static boolean createKey(REGISTRY_ROOT_KEY rootKey, String parent, String name) {
+ Advapi32 advapi32;
+ IntByReference hkResult, dwDisposition;
+ int handle = 0;
+ boolean ret = false;
+
+ advapi32 = Advapi32.INSTANCE;
+ hkResult = new IntByReference();
+ dwDisposition = new IntByReference();
+ handle = openKey(rootKey, parent, WINNT.KEY_READ);
+
+ if(handle != 0) {
+
+ if(advapi32.RegCreateKeyEx(handle, name, 0, null, WINNT.REG_OPTION_NON_VOLATILE, WINNT.KEY_READ, null,
+ hkResult, dwDisposition) == WINERROR.ERROR_SUCCESS) {
+ ret = true;
+ advapi32.RegCloseKey(hkResult.getValue());
+
+ } else {
+ ret = false;
+ }
+ advapi32.RegCloseKey(handle);
+ }
+ return(ret);
+ }
+
+ /**
+ * Delete a key.
+ *
+ * @param rootKey root key
+ * @param parent name of parent key
+ * @param name key name
+ * @return true on success
+ */
+ public static boolean deleteKey(REGISTRY_ROOT_KEY rootKey, String parent, String name) {
+ Advapi32 advapi32;
+ int handle = 0;
+ boolean ret = false;
+
+ advapi32 = Advapi32.INSTANCE;
+ handle = openKey(rootKey, parent, WINNT.KEY_READ);
+
+ if(handle != 0) {
+
+ if(advapi32.RegDeleteKey(handle, name) == WINERROR.ERROR_SUCCESS) {
+ ret = true;
+
+ } else {
+ ret = false;
+ }
+ advapi32.RegCloseKey(handle);
+ }
+ return(ret);
+ }
+
+ /**
+ * Get all sub keys of a key.
+ *
+ * @param rootKey root key
+ * @param parent key name
+ * @return array with all sub key names
+ */
+ public static String[] getSubKeys(REGISTRY_ROOT_KEY rootKey, String parent) {
+ Advapi32 advapi32;
+ int handle = 0, dwIndex;
+ char[] lpName;
+ IntByReference lpcName;
+ WINBASE.FILETIME lpftLastWriteTime;
+ TreeSet subKeys = new TreeSet();
+
+ advapi32 = Advapi32.INSTANCE;
+ handle = openKey(rootKey, parent, WINNT.KEY_READ);
+ lpName = new char[256];
+ lpcName = new IntByReference(256);
+ lpftLastWriteTime = new WINBASE.FILETIME();
+
+ if(handle != 0) {
+ dwIndex = 0;
+
+ while(advapi32.RegEnumKeyEx(handle, dwIndex, lpName, lpcName, null,
+ null, null, lpftLastWriteTime) == WINERROR.ERROR_SUCCESS) {
+ subKeys.add(new String(lpName, 0, lpcName.getValue()));
+ lpcName.setValue(256);
+ dwIndex++;
+ }
+ advapi32.RegCloseKey(handle);
+ }
+
+ return(subKeys.toArray(new String[]{}));
+ }
+
+ /**
+ * Get all values under a key.
+ *
+ * @param rootKey root key
+ * @param key jey name
+ * @throws java.io.UnsupportedEncodingException on error
+ * @return TreeMap with name and value pairs
+ */
+ public static TreeMap getValues(REGISTRY_ROOT_KEY rootKey, String key) throws UnsupportedEncodingException {
+ Advapi32 advapi32;
+ int handle = 0, dwIndex, result = 0;
+ char[] lpValueName;
+ byte[] lpData;
+ IntByReference lpcchValueName, lpType, lpcbData;
+ String name;
+ TreeMap values = new TreeMap(String.CASE_INSENSITIVE_ORDER);
+
+ advapi32 = Advapi32.INSTANCE;
+ handle = openKey(rootKey, key, WINNT.KEY_READ);
+ lpValueName = new char[16384];
+ lpcchValueName = new IntByReference(16384);
+ lpType = new IntByReference();
+ lpData = new byte[1];
+ lpcbData = new IntByReference();
+
+ if(handle != 0) {
+ dwIndex = 0;
+
+ do {
+ lpcbData.setValue(0);
+ result = advapi32.RegEnumValue(handle, dwIndex, lpValueName, lpcchValueName, null,
+ lpType, lpData, lpcbData);
+
+ if(result == WINERROR.ERROR_MORE_DATA) {
+ lpData = new byte[lpcbData.getValue()];
+ lpcchValueName = new IntByReference(16384);
+ result = advapi32.RegEnumValue(handle, dwIndex, lpValueName, lpcchValueName, null,
+ lpType, lpData, lpcbData);
+
+ if(result == WINERROR.ERROR_SUCCESS) {
+ name = new String(lpValueName, 0, lpcchValueName.getValue());
+
+ switch(lpType.getValue()) {
+ case WINNT.REG_SZ:
+ values.put(name, convertBufferToString(lpData));
+ break;
+ case WINNT.REG_DWORD:
+ values.put(name, convertBufferToInt(lpData));
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ dwIndex++;
+ } while(result == WINERROR.ERROR_SUCCESS);
+
+ advapi32.RegCloseKey(handle);
+ }
+ return(values);
+ }
+}
diff --git a/app/src/processing/app/windows/WINBASE.java b/app/src/processing/app/windows/WINBASE.java
new file mode 100644
index 000000000..c4807cc90
--- /dev/null
+++ b/app/src/processing/app/windows/WINBASE.java
@@ -0,0 +1,43 @@
+/*
+ * WINBASE.java
+ *
+ * Created on 5. September 2007, 11:24
+ *
+ * To change this template, choose Tools | Template Manager
+ * and open the template in the editor.
+ */
+
+package processing.app.windows;
+
+import com.sun.jna.Pointer;
+import com.sun.jna.Structure;
+
+/**
+ *
+ * @author TB
+ */
+public interface WINBASE {
+/*
+typedef struct _SECURITY_ATTRIBUTES {
+ DWORD nLength;
+ LPVOID lpSecurityDescriptor;
+ BOOL bInheritHandle;
+} SECURITY_ATTRIBUTES,
+ *PSECURITY_ATTRIBUTES,
+ *LPSECURITY_ATTRIBUTES;*/
+ public static class SECURITY_ATTRIBUTES extends Structure {
+ public int nLength;
+ public Pointer lpSecurityDescriptor;
+ public boolean bInheritHandle;
+ }
+
+/*
+typedef struct _FILETIME {
+ DWORD dwLowDateTime;
+ DWORD dwHighDateTime;
+} FILETIME, *PFILETIME, *LPFILETIME;*/
+ public static class FILETIME extends Structure {
+ public int dwLowDateTime;
+ public int dwHighDateTime;
+ }
+}
diff --git a/app/src/processing/app/windows/WINERROR.java b/app/src/processing/app/windows/WINERROR.java
new file mode 100644
index 000000000..3e1146e93
--- /dev/null
+++ b/app/src/processing/app/windows/WINERROR.java
@@ -0,0 +1,22 @@
+/*
+ * WINERROR.java
+ *
+ * Created on 7. August 2007, 08:09
+ *
+ * To change this template, choose Tools | Template Manager
+ * and open the template in the editor.
+ */
+
+package processing.app.windows;
+
+
+/**
+ *
+ * @author TB
+ */
+public interface WINERROR {
+ public final static int ERROR_SUCCESS = 0;
+ public final static int NO_ERROR = 0;
+ public final static int ERROR_FILE_NOT_FOUND = 2;
+ public final static int ERROR_MORE_DATA = 234;
+}
diff --git a/app/src/processing/app/windows/WINNT.java b/app/src/processing/app/windows/WINNT.java
new file mode 100644
index 000000000..89aa36168
--- /dev/null
+++ b/app/src/processing/app/windows/WINNT.java
@@ -0,0 +1,73 @@
+/*
+ * WINNT.java
+ *
+ * Created on 8. August 2007, 13:41
+ *
+ * To change this template, choose Tools | Template Manager
+ * and open the template in the editor.
+ */
+
+package processing.app.windows;
+
+/**
+ *
+ * @author TB
+ */
+public interface WINNT {
+ public final static int DELETE = 0x00010000;
+ public final static int READ_CONTROL = 0x00020000;
+ public final static int WRITE_DAC = 0x00040000;
+ public final static int WRITE_OWNER = 0x00080000;
+ public final static int SYNCHRONIZE = 0x00100000;
+
+ public final static int STANDARD_RIGHTS_REQUIRED = 0x000F0000;
+
+ public final static int STANDARD_RIGHTS_READ = READ_CONTROL;
+ public final static int STANDARD_RIGHTS_WRITE = READ_CONTROL;
+ public final static int STANDARD_RIGHTS_EXECUTE = READ_CONTROL;
+
+ public final static int STANDARD_RIGHTS_ALL = 0x001F0000;
+
+ public final static int SPECIFIC_RIGHTS_ALL = 0x0000FFFF;
+
+ public final static int GENERIC_EXECUTE = 0x20000000;
+
+ public final static int SERVICE_WIN32_OWN_PROCESS = 0x00000010;
+
+ public final static int KEY_QUERY_VALUE = 0x0001;
+ public final static int KEY_SET_VALUE = 0x0002;
+ public final static int KEY_CREATE_SUB_KEY = 0x0004;
+ public final static int KEY_ENUMERATE_SUB_KEYS = 0x0008;
+ public final static int KEY_NOTIFY = 0x0010;
+ public final static int KEY_CREATE_LINK = 0x0020;
+
+ public final static int KEY_READ = ((STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY) & (~SYNCHRONIZE));
+ public final static int KEY_WRITE = ((STANDARD_RIGHTS_WRITE | KEY_SET_VALUE | KEY_CREATE_SUB_KEY) & (~SYNCHRONIZE));
+
+ public final static int REG_NONE = 0; // No value type
+ public final static int REG_SZ = 1; // Unicode nul terminated string
+ public final static int REG_EXPAND_SZ = 2; // Unicode nul terminated string
+ // (with environment variable references)
+ public final static int REG_BINARY = 3; // Free form binary
+ public final static int REG_DWORD = 4; // 32-bit number
+ public final static int REG_DWORD_LITTLE_ENDIAN = 4; // 32-bit number (same as REG_DWORD)
+ public final static int REG_DWORD_BIG_ENDIAN = 5; // 32-bit number
+ public final static int REG_LINK = 6; // Symbolic Link (unicode)
+ public final static int REG_MULTI_SZ = 7; // Multiple Unicode strings
+ public final static int REG_RESOURCE_LIST = 8; // Resource list in the resource map
+ public final static int REG_FULL_RESOURCE_DESCRIPTOR = 9; // Resource list in the hardware description
+ public final static int REG_RESOURCE_REQUIREMENTS_LIST = 10;
+
+ public final static int REG_OPTION_RESERVED = 0x00000000; // Parameter is reserved
+ public final static int REG_OPTION_NON_VOLATILE = 0x00000000; // Key is preserved
+ // when system is rebooted
+ public final static int REG_OPTION_VOLATILE = 0x00000001; // Key is not preserved
+ // when system is rebooted
+ public final static int REG_OPTION_CREATE_LINK = 0x00000002; // Created key is a
+ // symbolic link
+ public final static int REG_OPTION_BACKUP_RESTORE = 0x00000004; // open for backup or restore
+ // special access rules
+ // privilege required
+ public final static int REG_OPTION_OPEN_LINK = 0x00000008; // Open symbolic link
+
+}
diff --git a/app/src/processing/app/windows/WINREG.java b/app/src/processing/app/windows/WINREG.java
new file mode 100644
index 000000000..988f7ef36
--- /dev/null
+++ b/app/src/processing/app/windows/WINREG.java
@@ -0,0 +1,21 @@
+/*
+ * WINREG.java
+ *
+ * Created on 17. August 2007, 14:32
+ *
+ * To change this template, choose Tools | Template Manager
+ * and open the template in the editor.
+ */
+
+package processing.app.windows;
+
+/**
+ *
+ * @author TB
+ */
+public interface WINREG {
+ public final static int HKEY_CLASSES_ROOT = 0x80000000;
+ public final static int HKEY_CURRENT_USER = 0x80000001;
+ public final static int HKEY_LOCAL_MACHINE = 0x80000002;
+ public final static int HKEY_USERS = 0x80000003;
+}
diff --git a/build/cmd/dist.sh b/build/cmd/dist.sh
new file mode 100755
index 000000000..38d295365
--- /dev/null
+++ b/build/cmd/dist.sh
@@ -0,0 +1,70 @@
+#!/bin/sh
+
+# only needed for core.jar and pde.jar, hmm
+ARCH=`uname`
+if [ $ARCH == "Darwin" ]
+then
+ BUILD=../macosx
+ REVISION=`head -1 ../../todo.txt | cut -c 1-4`
+elif [ $ARCH == "Cygwin" ]
+then
+ BUILD=../windows
+ REVISION=`head -c 4 ../../todo.txt`
+else
+ BUILD=../linux
+ REVISION=`head -c 4 ../../todo.txt`
+fi
+
+echo Creating command-line distribution for revision $REVISION...
+
+# remove any old boogers
+rm -rf processing
+rm -rf processing-*
+
+mkdir processing
+cp -r ../shared/lib processing/
+cp -r ../shared/libraries processing/
+cp ../../app/lib/antlr.jar processing/lib/
+cp ../../app/lib/ecj.jar processing/lib/
+cp ../../app/lib/jna.jar processing/lib/
+cp ../shared/revisions.txt processing/
+
+# add the libraries folder with source
+cp -r ../../net processing/libraries/
+cp -r ../../opengl processing/libraries/
+cp -r ../../serial processing/libraries/
+cp -r ../../pdf processing/libraries/
+cp -r ../../dxf processing/libraries/
+cp -r ../../xml processing/libraries/
+cp -r ../../candy processing/libraries/
+cp -r ../../video processing/libraries/
+
+# grab pde.jar and export from the working dir
+cp $BUILD/work/lib/pde.jar processing/lib/
+cp $BUILD/work/lib/core.jar processing/lib/
+
+# get platform-specific goodies from the dist dir
+install -m 755 dist/processing processing/processing
+
+# remove boogers
+find processing -name "*~" -exec rm -f {} ';'
+find processing -name ".DS_Store" -exec rm -f {} ';'
+find processing -name "._*" -exec rm -f {} ';'
+find processing -name "Thumbs.db" -exec rm -f {} ';'
+
+# clean out the cvs entries
+find processing -name "CVS" -exec rm -rf {} ';' 2> /dev/null
+find processing -name ".cvsignore" -exec rm -rf {} ';'
+find processing -name ".svn" -exec rm -rf {} 2> /dev/null ';'
+
+# zip it all up for release
+echo Creating tarball and finishing...
+P5=processing-cmd-$REVISION
+mv processing $P5
+
+zip -rq $P5.zip $P5
+#tar cfz $P5.tgz $P5
+# nah, keep the new directory around
+#rm -rf $P5
+
+#echo Done.
diff --git a/build/cmd/dist/processing b/build/cmd/dist/processing
new file mode 100644
index 000000000..8f6944154
--- /dev/null
+++ b/build/cmd/dist/processing
@@ -0,0 +1,20 @@
+ #!/bin/sh
+
+APPDIR="$(dirname -- "${0}")"
+
+# includes java/* in case a Java install is available
+for LIB in \
+ java/lib/rt.jar \
+ java/lib/tools.jar \
+ lib/*.jar \
+ ;
+do
+ CLASSPATH="${CLASSPATH}:${APPDIR}/${LIB}"
+done
+export CLASSPATH
+
+export PATH="${APPDIR}/java/bin:${PATH}"
+
+#java processing.app.Commander $*
+# if you know a better way to do this, submit it to dev.processing.org/bugs
+java processing.app.Commander "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9"
diff --git a/build/howto.txt b/build/howto.txt
new file mode 100755
index 000000000..d2103b03c
--- /dev/null
+++ b/build/howto.txt
@@ -0,0 +1,167 @@
+HOW TO BUILD PROCESSING ON YOUR FAVORITE PLATFORM
+
+If you have questions about the contents of this document,
+ask questions at the discourse section of the site:
+http://processing.org/discourse/yabb_beta/YaBB.cgi?board=os_core_pde
+
+
+////////////////////////////////////////////////////////////////////
+
+//// Steps for First Time Setup
+
+
+1. INSTALL DEVELOPMENT TOOLS
+
+1a. On Windows, install Cygwin. It's downloadable from
+ www.cygwin.com or specifically: www.cygwin.com/setup.exe
+
+** of the packages, begin with the defaults, and add:
+
++ subversion - used for version control
+
++ make, gcc-mingw, and g++ - used to build processing.exe
+ (this will also pull in gcc-core)
+
++ perl - use this version from cygwin, activestate or other windows
+ perl distributions have trouble
+
++ unzip, zip - for dealing with archives
+
++ included in the defaults, but make sure: coreutils, gzip, tar
+
++ not required but useful:
+ openssh - command line ssh client
+ nano - handy/simple text editor (gnu pico ripoff)
+
+** and be sure to leave the option selected for 'unix line endings'
+
+the cygwin installer is sometimes a little flakey, so it may take more
+than one try to get everything in there. in fact, it's often best to
+run the installer once, and let it install all its defaults, then run
+it again, and select the items above. it's also useful to run the
+installer every few months to keep things fresh.
+
+
+1b. On Mac OS X, install Apple's Developer Tools (Xcode).
+
+ You'll also need subversion: http://subversion.tigris.org/
+ Install it from Fink, Darwinports, or download as a package:
+ http://metissian.com/projects/macosx/subversion/
+
+
+1c. On Linux, you're pretty much on your own.. You need a pretty
+ standard development setup along with Subversion.
+
+
+2. GRAB THE CODE FROM DEV.PROCESSING.ORG
+
+As of August 12, 2005, we're no longer using CVS and have moved on to
+the brave new world of Subversion. This is scary but hopefully will
+alleviate some of the CVS annoyances.
+
+To get the code, type this from a prompt:
+svn co svn://processing.org/trunk/processing
+
+That part may take a while, especially for people outside the US or
+who have a slow internet connection. (The JRE binaries are stored in
+SVN so that we can properly test on the exact platform/runtime setup
+that we'll be releasing.)
+
+
+3. INSTALL QUICKTIME FOR JAVA (Windows users only)
+
+* You'll also need to install QuickTime for Java. Grab the QuickTime
+ (and iTunes) installer from: http://www.apple.com/quicktime/download/
+ or a version that doesn't include iTunes from here:
+ http://www.apple.com/quicktime/download/standalone.html
+ As of QuickTime 7 (iTunes 6), QuickTime for Java is mercifully
+ included by default.
+
+* QuickTime 6 is no longer supported. QuickTime Alternative has
+ never been supported. Just use QuickTime 7.
+
+
+4. BUILD IT
+
+# now to build for the first time:
+cd /path/to/processing/build/windows
+
+# or if you're on linux
+cd /path/to/processing/build/linux
+
+# let's say you're into black turtlenecks and jeans
+cd /path/to/processing/build/macosx
+
+# and then..
+./make.sh
+
+# if everything went well, you'll have no errors. (feel free to make
+# suggestions for things to include here for common problems)
+
+# then to run it
+./run.sh
+
+# each time you make a change, use make to build the thing
+# and run to get it up and running.
+
+
+////////////////////////////////////////////////////////////////////
+
+//// Updating to the Latest Version
+
+
+5a. Each time you want to update to latest version:
+
+cd /path/to/processing
+svn update
+
+
+5b. If you're getting strange errors when you try to build, especially
+ if new folders have been added to the Processing repository, remove
+ your 'work' folder and rebuild. Generally, this is a good idea to
+ do whenever a new release has been made, since that will involve
+ files that may have been changed (or folders that have been moved).
+
+# get to the processing folder
+cd /path/to/processing
+
+# remove the work directory
+cd build/yourplatform
+rm -rf work
+
+# and try again
+./make.sh
+
+Unfortunately there isn't a way to know if new folders have
+since been added. but if you're getting "class not found" errors
+while building, then that's a good indicator that something is
+missing from a subfolder.
+
+
+////////////////////////////////////////////////////////////////////
+
+//// The Frequently Asked Question
+
+- What about Eclipse? What about Ant? Command line sucks.
+
+The command line stuff isn't as scary as it might initially
+seem. Hopefully it's just a matter of following the instructions above
+(and being patient). If not, let us know (via the discourse board)
+where you have trouble so we can fix things.
+
+We're slowly moving development over to Eclipse, which will probably
+include Ant because of cross-platform dependencies. As of release 0140,
+major changes are being implemented to simplify the build process,
+which should mean that we're pretty close. The environment and all
+the libraries build properly with Eclipse, however we won't be
+documenting it until the dust has settled.
+
+Some progress has been made by John Houck to get the scripts working
+under ANT, progress can be tracked here:
+http://dev.processing.org/bugs/show_bug.cgi?id=151
+
+
+////////////////////////////////////////////////////////////////////
+
+
+Ben Fry - Updated 10 June 2008
diff --git a/build/javadoc/core/allclasses-frame.html b/build/javadoc/core/allclasses-frame.html
new file mode 100644
index 000000000..ae3faeefb
--- /dev/null
+++ b/build/javadoc/core/allclasses-frame.html
@@ -0,0 +1,87 @@
+
+
+
+
+
+All Classes
+
+
+
+
+
+
+
+
+
+
+All Classes
+
+
+
+This API (Application Programming Interface) document has pages corresponding to the items in the navigation bar, described as follows.
+Overview
+
+
+
+The Overview page is the front page of this API document and provides a list of all packages with a summary for each. This page can also contain an overall description of the set of packages.
+
+Package
+
+
+
+Each package has a page that contains a list of its classes and interfaces, with a summary for each. This page can contain four categories:
+
Interfaces (italic)
Classes
Enums
Exceptions
Errors
Annotation Types
+
+
+Class/Interface
+
+
+
+Each class, interface, nested class and nested interface has its own separate page. Each of these pages has three sections consisting of a class/interface description, summary tables, and detailed member descriptions:
+
Class inheritance diagram
Direct Subclasses
All Known Subinterfaces
All Known Implementing Classes
Class/interface declaration
Class/interface description
+
+
Nested Class Summary
Field Summary
Constructor Summary
Method Summary
+
+
Field Detail
Constructor Detail
Method Detail
+Each summary entry contains the first sentence from the detailed description for that item. The summary entries are alphabetical, while the detailed descriptions are in the order they appear in the source code. This preserves the logical groupings established by the programmer.
+
+
+Annotation Type
+
+
+
+Each annotation type has its own separate page with the following sections:
+
Annotation Type declaration
Annotation Type description
Required Element Summary
Optional Element Summary
Element Detail
+
+
+
+Enum
+
+
+
+Each enum has its own separate page with the following sections:
+
Enum declaration
Enum description
Enum Constant Summary
Enum Constant Detail
+
+
+Tree (Class Hierarchy)
+
+There is a Class Hierarchy page for all packages, plus a hierarchy for each package. Each hierarchy page contains a list of classes and a list of interfaces. The classes are organized by inheritance structure starting with java.lang.Object. The interfaces do not inherit from java.lang.Object.
+
When viewing the Overview page, clicking on "Tree" displays the hierarchy for all packages.
When viewing a particular package, class or interface page, clicking "Tree" displays the hierarchy for only that package.
+
+
+Deprecated API
+
+The Deprecated API page lists all of the API that have been deprecated. A deprecated API is not recommended for use, generally due to improvements, and a replacement API is usually given. Deprecated APIs may be removed in future implementations.
+
+Index
+
+The Index contains an alphabetic list of all classes, interfaces, constructors, methods, and fields.
+
+Prev/Next
+These links take you to the next or previous class, interface, package, or related page.
+Frames/No Frames
+These links show and hide the HTML frames. All pages are available with or without frames.
+
+
+Serialized Form
+Each serializable or externalizable class has a description of its serialization fields and methods. This information is of interest to re-implementors, not to developers using the API. While there is no link in the navigation bar, you can get to this information by going to any serialized class and clicking "Serialized Form" in the "See also" section of the class description.
+
Create a .vlw font on the fly from either a font name that's
+ installed on the system, or from a .ttf or .otf that's inside
+ the data folder of this sketch.
+
Preferred method of creating new PImage objects, ensures that a
+ reference to the parent PApplet is included, which makes save() work
+ without needing an absolute path.
+
Called by the browser or applet viewer to inform this applet
+ that it is being reclaimed and that it should destroy
+ any resources that it has allocated.
+
Overriding keyXxxxx(KeyEvent e) functions will cause the 'key',
+ 'keyCode', and 'keyEvent' variables to no longer work;
+ key events will no longer be queued until the end of draw();
+ and the keyPressed(), keyReleased() and keyTyped() methods
+ will no longer be called.
+
If you override this or any function that takes a "MouseEvent e"
+ without calling its super.mouseXxxx() then mouseX, mouseY,
+ mousePressed, and mouseEvent will no longer be set.
+
number format signed (or space)
+ Formats a number but leaves a blank space in the front
+ when it's positive so that it can be properly aligned with
+ numbers that have a negative sign in front of them.
+
Given an x and y coordinate, returns the x position of where
+ that point would be placed on screen, once affected by translate(),
+ scale(), or any other transformations.
+
Given an x and y coordinate, returns the y position of where
+ that point would be placed on screen, once affected by translate(),
+ scale(), or any other transformations.
+
Called in response to a resize event, handles setting the
+ new width and height internally, as well as re-allocating
+ the pixel buffer for the new size.
+
Called in response to a resize event, handles setting the
+ new width and height internally, as well as re-allocating
+ the pixel buffer for the new size.
+
Sets the text rendering/placement to be either SCREEN (direct
+ to the screen, exact coordinates, only use the font's original size)
+ or MODEL (the default, where text is manipulated by translate() and
+ can have a textSize).
+
remove(java.lang.Object object,
+ java.lang.reflect.Method method)
+
+
+ Removes first object/method pair matched (and only the first,
+ must be called multiple times if object is registered multiple times).
Removes first object/method pair matched (and only the first,
+ must be called multiple times if object is registered multiple times).
+ Does not shrink array afterwards, silently returns if method not found.
+
public static class PApplet.RendererChangeException
extends java.lang.RuntimeException
+
+
+
+Exception thrown when size() is called the first time.
+
+ This is used internally so that setup() is forced to run twice
+ when the renderer is changed. This is the only way for us to handle
+ invoking the new renderer while also in the midst of rendering.
+
+Base class for all sketches that use processing.core.
+
+ Note that you should not use AWT or Swing components inside a Processing
+ applet. The surface is made to automatically update itself, and will cause
+ problems with redraw of components drawn above it. If you'd like to
+ integrate other Java components, see below.
+
+ As of release 0145, Processing uses active mode rendering in all cases.
+ All animation tasks happen on the "Processing Animation Thread". The
+ setup() and draw() methods are handled by that thread, and events (like
+ mouse movement and key presses, which are fired by the event dispatch
+ thread or EDT) are queued to be (safely) handled at the end of draw().
+ For code that needs to run on the EDT, use SwingUtilities.invokeLater().
+ When doing so, be careful to synchronize between that code (since
+ invokeLater() will make your code run from the EDT) and the Processing
+ animation thread. Use of a callback function or the registerXxx() methods
+ in PApplet can help ensure that your code doesn't do something naughty.
+
+ As of release 0136 of Processing, we have discontinued support for versions
+ of Java prior to 1.5. We don't have enough people to support it, and for a
+ project of our size, we should be focusing on the future, rather than
+ working around legacy Java code. In addition, Java 1.5 gives us access to
+ better timing facilities which will improve the steadiness of animation.
+
+ This class extends Applet instead of JApplet because 1) historically,
+ we supported Java 1.1, which does not include Swing (without an
+ additional, sizable, download), and 2) Swing is a bloated piece of crap.
+ A Processing applet is a heavyweight AWT component, and can be used the
+ same as any other AWT component, with or without Swing.
+
+ Similarly, Processing runs in a Frame and not a JFrame. However, there's
+ nothing to prevent you from embedding a PApplet into a JFrame, it's just
+ that the base version uses a regular AWT frame because there's simply
+ no need for swing in that context. If people want to use Swing, they can
+ embed themselves as they wish.
+
+ It is possible to use PApplet, along with core.jar in other projects.
+ In addition to enabling you to use Java 1.5+ features with your sketch,
+ this also allows you to embed a Processing drawing area into another Java
+ application. This means you can use standard GUI controls with a Processing
+ sketch. Because AWT and Swing GUI components cannot be used on top of a
+ PApplet, you can instead embed the PApplet inside another GUI the way you
+ would any other Component.
+
+ It is also possible to resize the Processing window by including
+ frame.setResizable(true) inside your setup() method.
+ Note that the Java method frame.setSize() will not work unless
+ you first set the frame to be resizable.
+
+ Because the default animation thread will run at 60 frames per second,
+ an embedded PApplet can make the parent sluggish. You can use frameRate()
+ to make it update less often, or you can use noLoop() and loop() to disable
+ and then re-enable looping. If you want to only update the sketch
+ intermittently, use noLoop() inside setup(), and redraw() whenever
+ the screen needs to be updated once (or loop() to re-enable the animation
+ thread). The following example embeds a sketch and also uses the noLoop()
+ and redraw() methods. You need not use noLoop() and redraw() when embedding
+ if you want your application to animate continuously.
+
+ public class ExampleFrame extends Frame {
+
+ public ExampleFrame() {
+ super("Embedded PApplet");
+
+ setLayout(new BorderLayout());
+ PApplet embed = new Embedded();
+ add(embed, BorderLayout.CENTER);
+
+ // important to call this whenever embedding a PApplet.
+ // It ensures that the animation thread is started and
+ // that other internal variables are properly set.
+ embed.init();
+ }
+ }
+
+ public class Embedded extends PApplet {
+
+ public void setup() {
+ // original setup code here ...
+ size(400, 400);
+
+ // prevent thread from starving everything else
+ noLoop();
+ }
+
+ public void draw() {
+ // drawing code goes here
+ }
+
+ public void mousePressed() {
+ // do something based on mouse movement
+
+ // update the screen (run draw once)
+ redraw();
+ }
+ }
+
+
+
Processing on multiple displays
+
I was asked about Processing with multiple displays, and for lack of a
+ better place to document it, things will go here.
+
You can address both screens by making a window the width of both,
+ and the height of the maximum of both screens. In this case, do not use
+ present mode, because that's exclusive to one screen. Basically it'll
+ give you a PApplet that spans both screens. If using one half to control
+ and the other half for graphics, you'd just have to put the 'live' stuff
+ on one half of the canvas, the control stuff on the other. This works
+ better in windows because on the mac we can't get rid of the menu bar
+ unless it's running in present mode.
+
For more control, you need to write straight java code that uses p5.
+ You can create two windows, that are shown on two separate screens,
+ that have their own PApplet. this is just one of the tradeoffs of one of
+ the things that we don't support in p5 from within the environment
+ itself (we must draw the line somewhere), because of how messy it would
+ get to start talking about multiple screens. It's also not that tough to
+ do by hand w/ some Java code.
arraycopy(java.lang.Object src,
+ int srcPosition,
+ java.lang.Object dst,
+ int dstPosition,
+ int length)
+
+
+ Deprecated.Use arrayCopy() instead.
+
+
+
+static void
+
arrayCopy(java.lang.Object src,
+ int srcPosition,
+ java.lang.Object dst,
+ int dstPosition,
+ int length)
+
+
+ Calls System.arraycopy(), included here so that we can
+ avoid people needing to learn about the System object
+ before they can just copy an array.
beginRaw(java.lang.String renderer,
+ java.lang.String filename)
+
+
+ Begin recording raw shape data to a renderer of the specified type,
+ using the width and height of the main drawing surface.
+
+
+
+ void
+
beginRecord(PGraphics recorder)
+
+
+ Begin recording (echoing) commands to the specified PGraphics object.
beginRecord(java.lang.String renderer,
+ java.lang.String filename)
+
+
+ Begin recording to a new renderer of the specified type, using the width
+ and height of the main drawing surface.
createFont(java.lang.String name,
+ float size,
+ boolean smooth,
+ char[] charset)
+
+
+ Create a .vlw font on the fly from either a font name that's
+ installed on the system, or from a .ttf or .otf that's inside
+ the data folder of this sketch.
createGraphics(int iwidth,
+ int iheight,
+ java.lang.String irenderer,
+ java.lang.String ipath)
+
+
+ Create an offscreen graphics surface for drawing, in this case
+ for a renderer that writes to a file (such as PDF or DXF).
createImage(int wide,
+ int high,
+ int format)
+
+
+ Preferred method of creating new PImage objects, ensures that a
+ reference to the parent PApplet is included, which makes save() work
+ without needing an absolute path.
createOutput(java.lang.String filename)
+
+
+ Similar to createInput() (formerly openStream), this creates a Java
+ OutputStream for a given filename or path.
delay(int napTime)
+
+
+ The delay() function causes the program to halt for a specified time.
+
+
+
+ void
+
destroy()
+
+
+ Called by the browser or applet viewer to inform this applet
+ that it is being reclaimed and that it should destroy
+ any resources that it has allocated.
+
+
+
+ void
+
die(java.lang.String what)
+
+
+ Function for an applet/application to kill itself and
+ display an error.
+
+
+
+ void
+
die(java.lang.String what,
+ java.lang.Exception e)
+
+
+ Same as above but with an exception.
join(java.lang.String[] str,
+ char separator)
+
+
+ Join an array of Strings together as a single String,
+ separated by the whatever's passed in for the separator.
+
+
+
+static java.lang.String
+
join(java.lang.String[] str,
+ java.lang.String separator)
+
+
+ Join an array of Strings together as a single String,
+ separated by the whatever's passed in for the separator.
+
+
+
+ void
+
keyPressed()
+
+
+ Called each time a single key on the keyboard is pressed.
+
+
+
+ void
+
keyPressed(java.awt.event.KeyEvent e)
+
+
+ Overriding keyXxxxx(KeyEvent e) functions will cause the 'key',
+ 'keyCode', and 'keyEvent' variables to no longer work;
+ key events will no longer be queued until the end of draw();
+ and the keyPressed(), keyReleased() and keyTyped() methods
+ will no longer be called.
loadImage(java.lang.String filename,
+ java.lang.String extension)
+
+
+ Identical to loadImage, but allows you to specify the type of
+ image by its extension.
+
+
+
+ void
+
loadPixels()
+
+
+ Override the g.pixels[] function to set the pixels[] array
+ that's part of the PApplet object.
main(java.lang.String[] args)
+
+
+ main() method for running this class from the command line.
+
+
+
+static float
+
map(float value,
+ float istart,
+ float istop,
+ float ostart,
+ float ostop)
+
+
+ Convenience function to map a variable from one coordinate space
+ to another.
match(java.lang.String what,
+ java.lang.String regexp)
+
+
+ Match a string with a regular expression, and returns the match as an
+ array.
+
+
+
+static java.lang.String[][]
+
matchAll(java.lang.String what,
+ java.lang.String regexp)
+
+
+ Identical to match(), except that it returns an array of all matches in
+ the specified String, rather than just the first.
+
+
+
+static float
+
max(float[] list)
+
+
+ Find the maximum value in an array.
mousePressed()
+
+
+ Mouse has been pressed, and should be considered "down"
+ until mouseReleased() is called.
+
+
+
+ void
+
mousePressed(java.awt.event.MouseEvent e)
+
+
+ If you override this or any function that takes a "MouseEvent e"
+ without calling its super.mouseXxxx() then mouseX, mouseY,
+ mousePressed, and mouseEvent will no longer be set.
+
+
+
+ void
+
mouseReleased()
+
+
+ Mouse button has been released.
nfp(int num,
+ int digits)
+
+
+ number format positive (or plus)
+ Formats a number, always placing a - or + sign
+ in the front when it's negative or positive.
+
+
+
+static java.lang.String[]
+
nfs(float[] num,
+ int left,
+ int right)
+
+
+ Number formatter that takes into account whether the number
+ has a sign (positive, negative, etc) in front of it.
nfs(int num,
+ int digits)
+
+
+ number format signed (or space)
+ Formats a number but leaves a blank space in the front
+ when it's positive so that it can be properly aligned with
+ numbers that have a negative sign in front of them.
+
+
+
+ void
+
noCursor()
+
+
+ Hide the cursor by creating a transparent image
+ and using it as a custom cursor.
parseInt(java.lang.String what)
+
+
+ Parse a String into an int value.
+
+
+
+static int[]
+
parseInt(java.lang.String[] what)
+
+
+ Make an array of int elements from an array of String objects.
+
+
+
+static int[]
+
parseInt(java.lang.String[] what,
+ int missing)
+
+
+ Make an array of int elements from an array of String objects.
+
+
+
+static int
+
parseInt(java.lang.String what,
+ int otherwise)
+
+
+ Parse a String to an int, and provide an alternate value that
+ should be used when the number is invalid.
save(java.lang.String filename)
+
+
+ Intercepts any relative paths to make them absolute (relative
+ to the sketch folder) before passing to save() in PImage.
+
+
+
+static void
+
saveBytes(java.io.File file,
+ byte[] buffer)
+
+
+ Saves bytes to a specific File location specified by the user.
+
+
+
+static void
+
saveBytes(java.io.OutputStream output,
+ byte[] buffer)
+
+
+ Spews a buffer of bytes to an OutputStream.
+
+
+
+ void
+
saveBytes(java.lang.String filename,
+ byte[] buffer)
+
+
+ Saves bytes to a file to inside the sketch folder.
+
+
+
+ java.io.File
+
saveFile(java.lang.String where)
+
+
+ Identical to savePath(), but returns a File object.
+
+
+
+ void
+
saveFrame()
+
+
+ Grab an image of what's currently in the drawing area and save it
+ as a .tif or .tga file.
+
+
+
+ void
+
saveFrame(java.lang.String what)
+
+
+ Save the current frame as a .tif or .tga image.
+
+
+
+ java.lang.String
+
savePath(java.lang.String where)
+
+
+ Returns a path inside the applet folder to save to.
saveStream(java.io.File targetFile,
+ java.lang.String sourceLocation)
+
+
+ Identical to the other saveStream(), but writes to a File
+ object, for greater control over the file location.
+
+
+
+ void
+
saveStream(java.lang.String targetFilename,
+ java.lang.String sourceLocation)
+
+
+ Save the contents of a stream to a file in the sketch folder.
size(int iwidth,
+ int iheight,
+ java.lang.String irenderer,
+ java.lang.String ipath)
+
+
+ Creates a new PGraphics object and sets it to the specified size.
split(java.lang.String what,
+ char delim)
+
+
+ Split a string into pieces along a specific character.
+
+
+
+static java.lang.String[]
+
split(java.lang.String what,
+ java.lang.String delim)
+
+
+ Split a String on a specific delimiter.
+
+
+
+static java.lang.String[]
+
splitTokens(java.lang.String what)
+
+
+ Split the provided String at wherever whitespace occurs.
+
+
+
+static java.lang.String[]
+
splitTokens(java.lang.String what,
+ java.lang.String delim)
+
+
+ Splits a string into pieces, using any of the chars in the
+ String 'delim' as separator characters.
+public static final java.lang.String javaVersionName
+
+
Full name of the Java version (i.e. 1.5.0_11).
+ Prior to 0125, this was only the first three digits.
+
+
+
+
+
+
+
+javaVersion
+
+public static final float javaVersion
+
+
Version of Java that's in use, whether 1.1 or 1.3 or whatever,
+ stored as a float.
+
+ Note that because this is stored as a float, the values may
+ not be exactly 1.3 or 1.4. Instead, make sure you're
+ comparing against 1.3f or 1.4f, which will have the same amount
+ of error (i.e. 1.40000001). This could just be a double, but
+ since Processing only uses floats, it's safer for this to be a float
+ because there's no good way to specify a double with the preproc.
+
+
+
+
+
+
+
+platform
+
+public static int platform
+
+
Current platform in use, one of the
+ PConstants WINDOWS, MACOSX, MACOS9, LINUX or OTHER.
+
+
+
+
+
+
+
+MENU_SHORTCUT
+
+public static final int MENU_SHORTCUT
+
+
Modifier flags for the shortcut key used to trigger menus.
+ (Cmd on Mac OS X, Ctrl on Linux and Windows)
+
The PGraphics renderer associated with this PApplet
+
+
+
+
+
+
+
+frame
+
+public java.awt.Frame frame
+
+
The frame containing this applet (if any)
+
+
+
+
+
+
+
+screen
+
+public java.awt.Dimension screen
+
+
The screen size when the applet was started.
+
+ Access this via screen.width and screen.height. To make an applet
+ run at full screen, use size(screen.width, screen.height).
+
+ If you have multiple displays, this will be the size of the main
+ display. Running full screen across multiple displays isn't
+ particularly supported, and requires more monkeying with the values.
+ This probably can't/won't be fixed until/unless I get a dual head
+ system.
+
+ Note that this won't update if you change the resolution
+ of your screen once the the applet is running.
+
+ This variable is not static, because future releases need to be better
+ at handling multiple displays.
+
Minimum dimensions for the window holding an applet.
+ This varies between platforms, Mac OS X 10.3 can do any height
+ but requires at least 128 pixels width. Windows XP has another
+ set of limitations. And for all I know, Linux probably lets you
+ make windows with negative sizes.
+
true if no size() command has been executed. This is used to wait until
+ a size has been set before placing in the window and showing it.
+
+
+
+
+
+
+
+pixels
+
+public int[] pixels
+
+
Pixel buffer from this applet's PGraphics.
+
+ When used with OpenGL or Java2D, this value will
+ be null until loadPixels() has been called.
+
+
+
+
+
+
+
+width
+
+public int width
+
+
width of this applet's associated PGraphics
+
+
+
+
+
+
+
+height
+
+public int height
+
+
height of this applet's associated PGraphics
+
+
+
+
+
+
+
+mouseX
+
+public int mouseX
+
+
current x position of the mouse
+
+
+
+
+
+
+
+mouseY
+
+public int mouseY
+
+
current y position of the mouse
+
+
+
+
+
+
+
+pmouseX
+
+public int pmouseX
+
+
Previous x/y position of the mouse. This will be a different value
+ when inside a mouse handler (like the mouseMoved() method) versus
+ when inside draw(). Inside draw(), pmouseX is updated once each
+ frame, but inside mousePressed() and friends, it's updated each time
+ an event comes through. Be sure to use only one or the other type of
+ means for tracking pmouseX and pmouseY within your sketch, otherwise
+ you're gonna run into trouble.
+
+
+
+
+
+
+
+pmouseY
+
+public int pmouseY
+
+
Previous x/y position of the mouse. This will be a different value
+ when inside a mouse handler (like the mouseMoved() method) versus
+ when inside draw(). Inside draw(), pmouseX is updated once each
+ frame, but inside mousePressed() and friends, it's updated each time
+ an event comes through. Be sure to use only one or the other type of
+ means for tracking pmouseX and pmouseY within your sketch, otherwise
+ you're gonna run into trouble.
+
+
+
+
+
+
+
+firstMouse
+
+public boolean firstMouse
+
+
Used to set pmouseX/Y to mouseX/Y the first time mouseX/Y are used,
+ otherwise pmouseX/Y are always zero, causing a nasty jump.
+
+ Just using (frameCount == 0) won't work since mouseXxxxx()
+ may not be called until a couple frames into things.
+
+
+
+
+
+
+
+mouseButton
+
+public int mouseButton
+
+
Last mouse button pressed, one of LEFT, CENTER, or RIGHT.
+
+ If running on Mac OS, a ctrl-click will be interpreted as
+ the righthand mouse button (unlike Java, which reports it as
+ the left mouse).
+
+
+
+
+
+
+
+mousePressed
+
+public boolean mousePressed
+
+
+
+
+
+
+
+mouseEvent
+
+public java.awt.event.MouseEvent mouseEvent
+
+
+
+
+
+
+
+key
+
+public char key
+
+
Last key pressed.
+
+ If it's a coded key, i.e. UP/DOWN/CTRL/SHIFT/ALT,
+ this will be set to CODED (0xffff or 65535).
+
+
+
+
+
+
+
+keyCode
+
+public int keyCode
+
+
When "key" is set to CODED, this will contain a Java key code.
+
+ For the arrow keys, keyCode will be one of UP, DOWN, LEFT and RIGHT.
+ Also available are ALT, CONTROL and SHIFT. A full set of constants
+ can be obtained from java.awt.event.KeyEvent, from the VK_XXXX variables.
+
+
+
+
+
+
+
+keyPressed
+
+public boolean keyPressed
+
+
true if the mouse is currently pressed.
+
+
+
+
+
+
+
+keyEvent
+
+public java.awt.event.KeyEvent keyEvent
+
+
the last KeyEvent object passed into a mouse function.
+
+
+
+
+
+
+
+focused
+
+public boolean focused
+
+
Gets set to true/false as the applet gains/loses focus.
+
+
+
+
+
+
+
+online
+
+public boolean online
+
+
true if the applet is online.
+
+ This can be used to test how the applet should behave
+ since online situations are different (no file writing, etc).
+
+
+
+
+
+
+
+frameRate
+
+public float frameRate
+
+
The current value of frames per second.
+
+ The initial value will be 10 fps, and will be updated with each
+ frame thereafter. The value is not instantaneous (since that
+ wouldn't be very useful since it would jump around so much),
+ but is instead averaged (integrated) over several frames.
+ As such, this value won't be valid until after 5-10 frames.
+
+
+
+
+
+
+
+frameCount
+
+public int frameCount
+
+
How many frames have been displayed since the applet started.
+
+ This value is read-only do not attempt to set it,
+ otherwise bad things will happen.
+
+ Inside setup(), frameCount is 0.
+ For the first iteration of draw(), frameCount will equal 1.
+
+
+
+
+
+
+
+finished
+
+public boolean finished
+
+
true if this applet has had it.
+
+
+
+
+
+
+
+ARGS_EDITOR_LOCATION
+
+public static final java.lang.String ARGS_EDITOR_LOCATION
+
+
Position of the upper-lefthand corner of the editor window
+ that launched this applet.
+
+public static final java.lang.String ARGS_EXTERNAL
+
+
Location for where to position the applet window on screen.
+
+ This is used by the editor to when saving the previous applet
+ location, or could be used by other classes to launch at a
+ specific position on-screen.
+
By trial and error, four image loading threads seem to work best when
+ loading images from online. This is consistent with the number of open
+ connections that web browsers will maintain. The variable is made public
+ (however no accessor has been added since it's esoteric) if you really
+ want to have control over the value used. For instance, when loading local
+ files, it might be better to only have a single thread (or two) loading
+ images so that you're disk isn't simply jumping around.
+
+
+
+
+
+
+
+selectedFile
+
+public java.io.File selectedFile
+
+
+
+
+
+
+
+ICON_IMAGE
+
+public static final byte[] ICON_IMAGE
+
+
GIF image of the Processing logo.
+
+
+
+
+
+
+
+
+
+
+
+Constructor Detail
+
+
+
+
+PApplet
+
+public PApplet()
+
+
+
+
+
+
+
+
+
+Method Detail
+
+
+
+
+init
+
+public void init()
+
+
+
Overrides:
init in class java.applet.Applet
+
+
+
+
+
+
+
+
+getSketchWidth
+
+public int getSketchWidth()
+
+
+
+
+
+
+
+
+
+
+
+getSketchHeight
+
+public int getSketchHeight()
+
+
+
+
+
+
+
+
+
+
+
+getSketchRenderer
+
+public java.lang.String getSketchRenderer()
+
+
+
+
+
+
+
+
+
+
+
+start
+
+public void start()
+
+
Called by the browser or applet viewer to inform this applet that it
+ should start its execution. It is called after the init method and
+ each time the applet is revisited in a Web page.
+
+ Called explicitly via the first call to PApplet.paint(), because
+ PAppletGL needs to have a usable screen before getting things rolling.
+
+
+
Overrides:
start in class java.applet.Applet
+
+
+
+
+
+
+
+
+stop
+
+public void stop()
+
+
Called by the browser or applet viewer to inform
+ this applet that it should stop its execution.
+
+ Unfortunately, there are no guarantees from the Java spec
+ when or if stop() will be called (i.e. on browser quit,
+ or when moving between web pages), and it's not always called.
+
+
+
Overrides:
stop in class java.applet.Applet
+
+
+
+
+
+
+
+
+destroy
+
+public void destroy()
+
+
Called by the browser or applet viewer to inform this applet
+ that it is being reclaimed and that it should destroy
+ any resources that it has allocated.
+
+ This also attempts to call PApplet.stop(), in case there
+ was an inadvertent override of the stop() function by a user.
+
+ destroy() supposedly gets called as the applet viewer
+ is shutting down the applet. stop() is called
+ first, and then destroy() to really get rid of things.
+ no guarantees on when they're run (on browser quit, or
+ when moving between pages), though.
+
Starts up and creates a two-dimensional drawing surface,
+ or resizes the current drawing surface.
+
+ This should be the first thing called inside of setup().
+
+ If using Java 1.3 or later, this will default to using
+ PGraphics2, the Java2D-based renderer. If using Java 1.1,
+ or if PGraphics2 is not available, then PGraphics will be used.
+ To set your own renderer, use the other version of the size()
+ method that takes a renderer as its last parameter.
+
+ If called once a renderer has already been set, this will
+ use the previous renderer and simply resize it.
+
+
+
+
+
+
+
+
+
+
+
+size
+
+public void size(int iwidth,
+ int iheight,
+ java.lang.String irenderer)
Creates a new PGraphics object and sets it to the specified size.
+
+ Note that you cannot change the renderer once outside of setup().
+ In most cases, you can call size() to give it a new size,
+ but you need to always ask for the same renderer, otherwise
+ you're gonna run into trouble.
+
+ The size() method should *only* be called from inside the setup() or
+ draw() methods, so that it is properly run on the main animation thread.
+ To change the size of a PApplet externally, use setSize(), which will
+ update the component size, and queue a resize of the renderer as well.
+
+
+
+
+
+
+
+
+
+
+
+createGraphics
+
+public PGraphicscreateGraphics(int iwidth,
+ int iheight,
+ java.lang.String irenderer)
+
+
Create an offscreen PGraphics object for drawing. This can be used
+ for bitmap or vector images drawing or rendering.
+
+
Do not use "new PGraphicsXxxx()", use this method. This method
+ ensures that internal variables are set up properly that tie the
+ new graphics context back to its parent PApplet.
+
The basic way to create bitmap images is to use the saveFrame()
+ function.
+
If you want to create a really large scene and write that,
+ first make sure that you've allocated a lot of memory in the Preferences.
+
If you want to create images that are larger than the screen,
+ you should create your own PGraphics object, draw to that, and use
+ save().
+ For now, it's best to use P3D in this scenario.
+ P2D is currently disabled, and the JAVA2D default will give mixed
+ results. An example of using P3D:
+
+
+ PGraphics big;
+
+ void setup() {
+ big = createGraphics(3000, 3000, P3D);
+
+ big.beginDraw();
+ big.background(128);
+ big.line(20, 1800, 1800, 900);
+ // etc..
+ big.endDraw();
+
+ // make sure the file is written to the sketch folder
+ big.save("big.tif");
+ }
+
+
+
It's important to always wrap drawing to createGraphics() with
+ beginDraw() and endDraw() (beginFrame() and endFrame() prior to
+ revision 0115). The reason is that the renderer needs to know when
+ drawing has stopped, so that it can update itself internally.
+ This also handles calling the defaults() method, for people familiar
+ with that.
+
It's not possible to use createGraphics() with the OPENGL renderer,
+ because it doesn't allow offscreen use.
+
With Processing 0115 and later, it's possible to write images in
+ formats other than the default .tga and .tiff. The exact formats and
+ background information can be found in the developer's reference for
+ PImage.save().
+
Create an offscreen graphics surface for drawing, in this case
+ for a renderer that writes to a file (such as PDF or DXF).
+
+
+
+
+
+
Parameters:
ipath - can be an absolute or relative path
+
+
+
+
+
+createImage
+
+public PImagecreateImage(int wide,
+ int high,
+ int format)
+
+
Preferred method of creating new PImage objects, ensures that a
+ reference to the parent PApplet is included, which makes save() work
+ without needing an absolute path.
+
If you override this or any function that takes a "MouseEvent e"
+ without calling its super.mouseXxxx() then mouseX, mouseY,
+ mousePressed, and mouseEvent will no longer be set.
+
+
+
Specified by:
mousePressed in interface java.awt.event.MouseListener
mouseMoved in interface java.awt.event.MouseMotionListener
+
+
+
+
+
+
+
+
+mousePressed
+
+public void mousePressed()
+
+
Mouse has been pressed, and should be considered "down"
+ until mouseReleased() is called. If you must, use
+ int button = mouseEvent.getButton();
+ to figure out which button was clicked. It will be one of:
+ MouseEvent.BUTTON1, MouseEvent.BUTTON2, MouseEvent.BUTTON3
+ Note, however, that this is completely inconsistent across
+ platforms.
+
+
+
+
+
+
+
+
+
+
+
+mouseReleased
+
+public void mouseReleased()
+
+
Mouse button has been released.
+
+
+
+
+
+
+
+
+
+
+
+mouseClicked
+
+public void mouseClicked()
+
+
When the mouse is clicked, mousePressed() will be called,
+ then mouseReleased(), then mouseClicked(). Note that
+ mousePressed is already false inside of mouseClicked().
+
+
+
+
+
+
+
+
+
+
+
+mouseDragged
+
+public void mouseDragged()
+
+
Mouse button is pressed and the mouse has been dragged.
+
+
+
+
+
+
+
+
+
+
+
+mouseMoved
+
+public void mouseMoved()
+
+
Mouse button is not pressed but the mouse has changed locations.
+
Overriding keyXxxxx(KeyEvent e) functions will cause the 'key',
+ 'keyCode', and 'keyEvent' variables to no longer work;
+ key events will no longer be queued until the end of draw();
+ and the keyPressed(), keyReleased() and keyTyped() methods
+ will no longer be called.
+
+
+
Specified by:
keyPressed in interface java.awt.event.KeyListener
keyReleased in interface java.awt.event.KeyListener
+
+
+
+
+
+
+
+
+keyTyped
+
+public void keyTyped(java.awt.event.KeyEvent e)
+
+
+
Specified by:
keyTyped in interface java.awt.event.KeyListener
+
+
+
+
+
+
+
+
+keyPressed
+
+public void keyPressed()
+
+
Called each time a single key on the keyboard is pressed.
+ Because of how operating systems handle key repeats, holding
+ down a key will cause multiple calls to keyPressed(), because
+ the OS repeat takes over.
+
+ Examples for key handling:
+ (Tested on Windows XP, please notify if different on other
+ platforms, I have a feeling Mac OS and Linux may do otherwise)
+
+ 1. Pressing 'a' on the keyboard:
+ keyPressed with key == 'a' and keyCode == 'A'
+ keyTyped with key == 'a' and keyCode == 0
+ keyReleased with key == 'a' and keyCode == 'A'
+
+ 2. Pressing 'A' on the keyboard:
+ keyPressed with key == 'A' and keyCode == 'A'
+ keyTyped with key == 'A' and keyCode == 0
+ keyReleased with key == 'A' and keyCode == 'A'
+
+ 3. Pressing 'shift', then 'a' on the keyboard (caps lock is off):
+ keyPressed with key == CODED and keyCode == SHIFT
+ keyPressed with key == 'A' and keyCode == 'A'
+ keyTyped with key == 'A' and keyCode == 0
+ keyReleased with key == 'A' and keyCode == 'A'
+ keyReleased with key == CODED and keyCode == SHIFT
+
+ 4. Holding down the 'a' key.
+ The following will happen several times,
+ depending on your machine's "key repeat rate" settings:
+ keyPressed with key == 'a' and keyCode == 'A'
+ keyTyped with key == 'a' and keyCode == 0
+ When you finally let go, you'll get:
+ keyReleased with key == 'a' and keyCode == 'A'
+
+ 5. Pressing and releasing the 'shift' key
+ keyPressed with key == CODED and keyCode == SHIFT
+ keyReleased with key == CODED and keyCode == SHIFT
+ (note there is no keyTyped)
+
+ 6. Pressing the tab key in an applet with Java 1.4 will
+ normally do nothing, but PApplet dynamically shuts
+ this behavior off if Java 1.4 is in use (tested 1.4.2_05 Windows).
+ Java 1.1 (Microsoft VM) passes the TAB key through normally.
+ Not tested on other platforms or for 1.3.
+
+
+
+
+
+
+
+
+
+
+
+
+keyReleased
+
+public void keyReleased()
+
+
See keyPressed().
+
+
+
+
+
+
+
+
+
+
+
+keyTyped
+
+public void keyTyped()
+
+
Only called for "regular" keys like letters,
+ see keyPressed() for full documentation.
+
focusLost in interface java.awt.event.FocusListener
+
+
+
+
+
+
+
+
+millis
+
+public int millis()
+
+
Get the number of milliseconds since the applet started.
+
+ This is a function, rather than a variable, because it may
+ change multiple times per frame.
+
+
+
+
+
+
+
+
+
+
+
+second
+
+public static int second()
+
+
Seconds position of the current time.
+
+
+
+
+
+
+
+
+
+
+
+minute
+
+public static int minute()
+
+
Minutes position of the current time.
+
+
+
+
+
+
+
+
+
+
+
+hour
+
+public static int hour()
+
+
Hour position of the current time in international format (0-23).
+
+ To convert this value to American time:
+
int yankeeHour = (hour() % 12);
+ if (yankeeHour == 0) yankeeHour = 12;
+
+
+
+
+
+
+
+
+
+
+
+day
+
+public static int day()
+
+
Get the current day of the month (1 through 31).
+
+ If you're looking for the day of the week (M-F or whatever)
+ or day of the year (1..365) then use java's Calendar.get()
+
+
+
+
+
+
+
+
+
+
+
+month
+
+public static int month()
+
+
Get the current month in range 1 through 12.
+
+
+
+
+
+
+
+
+
+
+
+year
+
+public static int year()
+
+
Get the current year.
+
+
+
+
+
+
+
+
+
+
+
+delay
+
+public void delay(int napTime)
+
+
The delay() function causes the program to halt for a specified time.
+ Delay times are specified in thousandths of a second. For example,
+ running delay(3000) will stop the program for three seconds and
+ delay(500) will stop the program for a half-second. Remember: the
+ display window is updated only at the end of draw(), so putting more
+ than one delay() inside draw() will simply add them together and the new
+ frame will be drawn when the total delay is over.
+
+ I'm not sure if this is even helpful anymore, as the screen isn't
+ updated before or after the delay, meaning which means it just
+ makes the app lock up temporarily.
+
+
+
+
+
+
+
+
+
+
+
+frameRate
+
+public void frameRate(float newRateTarget)
+
+
Set a target frameRate. This will cause delay() to be called
+ after each frame so that the sketch synchronizes to a particular speed.
+ Note that this only sets the maximum frame rate, it cannot be used to
+ make a slow sketch go faster. Sketches have no default frame rate
+ setting, and will attempt to use maximum processor power to achieve
+ maximum speed.
+
Get a param from the web page, or (eventually)
+ from a properties file.
+
+
+
+
+
+
+
+
+
+
+
+status
+
+public void status(java.lang.String what)
+
+
Show status in the status bar of a web browser, or in the
+ System.out console. Eventually this might show status in the
+ p5 environment itself, rather than relying on the console.
+
Launch a process using a platforms shell. This version uses an array
+ to make it easier to deal with spaces in the individual elements.
+ (This avoids the situation of trying to put single or double quotes
+ around different bits).
+
Same as above but with an exception. Also needs work.
+
+
+
+
+
+
+
+
+
+
+
+exit
+
+public void exit()
+
+
Call to safely exit the sketch when finished. For instance,
+ to render a single frame, save it, and quit.
+
+
+
+
+
+
+
+
+
+
+
+save
+
+public void save(java.lang.String filename)
+
+
Intercepts any relative paths to make them absolute (relative
+ to the sketch folder) before passing to save() in PImage.
+ (Changed in 0100)
+
+
+
+
+
+
+
+
+
+
+
+saveFrame
+
+public void saveFrame()
+
+
Grab an image of what's currently in the drawing area and save it
+ as a .tif or .tga file.
+
+ Best used just before endDraw() at the end of your draw().
+ This can only create .tif or .tga images, so if neither extension
+ is specified it defaults to writing a tiff and adds a .tif suffix.
+
+
+
+
+
+
+
+
+
+
+
+saveFrame
+
+public void saveFrame(java.lang.String what)
+
+
Save the current frame as a .tif or .tga image.
+
+ The String passed in can contain a series of # signs
+ that will be replaced with the screengrab number.
+
+ i.e. saveFrame("blah-####.tif");
+ // saves a numbered tiff image, replacing the
+ // #### signs with zeros and the frame number
Replace the cursor with the specified PImage. The x- and y-
+ coordinate of the center will be the center of the image.
+
+
+
+
+
+
+
+
+
+
+
+cursor
+
+public void cursor(PImage image,
+ int hotspotX,
+ int hotspotY)
+
+
Set a custom cursor to an image with a specific hotspot.
+ Only works with JDK 1.2 and later.
+ Currently seems to be broken on Java 1.4 for Mac OS X
+
+ Based on code contributed by Amit Pitaru, plus additional
+ code to handle Java versions via reflection by Jonathan Feinberg.
+ Reflection removed for release 0128 and later.
+
+
+
+
+
+
+
+
+
+
+
+cursor
+
+public void cursor()
+
+
Show the cursor after noCursor() was called.
+ Notice that the program remembers the last set cursor type
+
+
+
+
+
+
+
+
+
+
+
+noCursor
+
+public void noCursor()
+
+
Hide the cursor by creating a transparent image
+ and using it as a custom cursor.
+
Normalize a value to exist between 0 and 1 (inclusive).
+ Mathematically the opposite of lerp(), figures out what proportion
+ a particular value is relative to start and stop coordinates.
+
Convenience function to map a variable from one coordinate space
+ to another. Equivalent to unlerp() followed by lerp().
+
+
+
+
+
+
+
+
+
+
+
+random
+
+public final float random(float howbig)
+
+
Return a random number in the range [0, howbig).
+
+ The number returned will range from zero up to
+ (but not including) 'howbig'.
+
+
+
+
+
+
+
+
+
+
+
+random
+
+public final float random(float howsmall,
+ float howbig)
+
+
Return a random number in the range [howsmall, howbig).
+
+ The number returned will range from 'howsmall' up to
+ (but not including 'howbig'.
+
+ If howsmall is >= howbig, howsmall will be returned,
+ meaning that random(5, 5) will return 5 (useful)
+ and random(7, 4) will return 7 (not useful.. better idea?)
+
+
+
+
+
+
+
+
+
+
+
+randomSeed
+
+public final void randomSeed(long what)
+
+
+
+
+
+
+
+
+
+
+
+noise
+
+public float noise(float x)
+
+
Computes the Perlin noise function value at point x.
+
+
+
+
+
+
+
+
+
+
+
+noise
+
+public float noise(float x,
+ float y)
+
+
Computes the Perlin noise function value at the point x, y.
+
+
+
+
+
+
+
+
+
+
+
+noise
+
+public float noise(float x,
+ float y,
+ float z)
+
+
Computes the Perlin noise function value at x, y, z.
+
Load an image from the data folder or a local directory.
+ Supports .gif (including transparency), .tga, and .jpg images.
+ In Java 1.3 or later, .png images are
+
+ also supported.
+
+ Generally, loadImage() should only be used during setup, because
+ re-loading images inside draw() is likely to cause a significant
+ delay while memory is allocated and the thread blocks while waiting
+ for the image to load because loading is not asynchronous.
+
+ To load several images asynchronously, see more information in the
+ FAQ about writing your own threaded image loading method.
+
+ As of 0096, returns null if no image of that name is found,
+ rather than an error.
+
+ Release 0115 also provides support for reading TIFF and RLE-encoded
+ Targa (.tga) files written by Processing via save() and saveFrame().
+ Other TIFF and Targa files will probably not load, use a different
+ format (gif, jpg and png are safest bets) when creating images with
+ another application to use with Processing.
+
+ Also in release 0115, more image formats (BMP and others) can
+ be read when using Java 1.4 and later. Because many people still
+ use Java 1.1 and 1.3, these formats are not recommended for
+ work that will be posted on the web. To get a list of possible
+ image formats for use with Java 1.4 and later, use the following:
+ println(javax.imageio.ImageIO.getReaderFormatNames())
+
+ Images are loaded via a byte array that is passed to
+ Toolkit.createImage(). Unfortunately, we cannot use Applet.getImage()
+ because it takes a URL argument, which would be a pain in the a--
+ to make work consistently for online and local sketches.
+ Sometimes this causes problems, resulting in issues like
+ Bug 279
+ and
+ Bug 305.
+ In release 0115, everything was instead run through javax.imageio,
+ but that turned out to be very slow, see
+ Bug 392.
+ As a result, starting with 0116, the following happens:
+
+
TGA and TIFF images are loaded using the internal load methods.
+
JPG, GIF, and PNG images are loaded via loadBytes().
+
If the image still isn't loaded, it's passed to javax.imageio.
+
+ For releases 0116 and later, if you have problems such as those seen
+ in Bugs 279 and 305, use Applet.getImage() instead. You'll be stuck
+ with the limitations of getImage() (the headache of dealing with
+ online/offline use). Set up your own MediaTracker, and pass the resulting
+ java.awt.Image to the PImage constructor that takes an AWT image.
+
Create a .vlw font on the fly from either a font name that's
+ installed on the system, or from a .ttf or .otf that's inside
+ the data folder of this sketch.
+
+ Only works with Java 1.3 or later. Many .otf fonts don't seem
+ to be supported by Java, perhaps because they're CFF based?
+
+ Font names are inconsistent across platforms and Java versions.
+ On Mac OS X, Java 1.3 uses the font menu name of the font,
+ whereas Java 1.4 uses the PostScript name of the font. Java 1.4
+ on OS X will also accept the font menu name as well. On Windows,
+ it appears that only the menu names are used, no matter what
+ Java version is in use. Naming system unknown/untested for 1.5.
+
+ Use 'null' for the charset if you want to use any of the 65,536
+ unicode characters that exist in the font. Note that this can
+ produce an enormous file or may cause an OutOfMemoryError.
+
+
+
+
+
+
+
+
+
+
+
+selectInput
+
+public java.lang.String selectInput()
+
+
Open a platform-specific file chooser dialog to select a file for input.
+
+
+
+
+
+
+
Returns:
full path to the selected file, or null if no selection.
+ This method is useful if you want to use the facilities provided
+ by PApplet to easily open things from the data folder or from a URL,
+ but want an InputStream object so that you can use other Java
+ methods to take more control of how the stream is read.
+
+ If the requested item doesn't exist, null is returned.
+ (Prior to 0096, die() would be called, killing the applet)
+
+ For 0096+, the "data" folder is exported intact with subfolders,
+ and openStream() properly handles subdirectories from the data folder
+
+ If not online, this will also check to see if the user is asking
+ for a file whose name isn't properly capitalized. This helps prevent
+ issues when a sketch is exported to the web, where case sensitivity
+ matters, as opposed to Windows and the Mac OS default where
+ case sensitivity is preserved but ignored.
+
+ It is strongly recommended that libraries use this method to open
+ data files, so that the loading sequence is handled in the same way
+ as functions like loadBytes(), loadImage(), etc.
+
+ The filename passed in can be:
+
+
A URL, for instance openStream("http://processing.org/");
+
A file in the sketch's data folder
+
Another file to be opened locally (when running as an application)
+
Load data from a file and shove it into a String array.
+
+ Exceptions are handled internally, when an error, occurs, an
+ exception is printed to the console and 'null' is returned,
+ but the program continues running. This is a tradeoff between
+ 1) showing the user that there was a problem but 2) not requiring
+ that all i/o code is contained in try/catch blocks, for the sake
+ of new users (or people who are just trying to get things done
+ in a "scripting" fashion. If you want to handle exceptions,
+ use Java methods for I/O.
+
Similar to createInput() (formerly openStream), this creates a Java
+ OutputStream for a given filename or path. The file will be created in
+ the sketch folder, or in the same folder as an exported application.
+
+ If the path does not exist, intermediate folders will be created. If an
+ exception occurs, it will be printed to the console, and null will be
+ returned.
+
+ Future releases may also add support for handling HTTP POST via this
+ method (for better symmetry with createInput), however that's maybe a
+ little too clever (and then we'd have to add the same features to the
+ other file functions like createWriter). Who you callin' bloated?
+
Save the contents of a stream to a file in the sketch folder.
+ This is basically saveBytes(blah, loadBytes()), but done
+ more efficiently (and with less confusing syntax).
+
Identical to the other saveStream(), but writes to a File
+ object, for greater control over the file location.
+ Note that unlike other api methods, this will not automatically
+ compress or uncompress gzip files.
+
Saves bytes to a file to inside the sketch folder.
+ The filename can be a relative path, i.e. "poo/bytefun.txt"
+ would save to a file named "bytefun.txt" to a subfolder
+ called 'poo' inside the sketch folder. If the in-between
+ subfolders don't exist, they'll be created.
+
Prepend the sketch folder path to the filename (or path) that is
+ passed in. External libraries should use this function to save to
+ the sketch folder.
+
+ Note that when running as an applet inside a web browser,
+ the sketchPath will be set to null, because security restrictions
+ prevent applets from accessing that information.
+
+ This will also cause an error if the sketch is not inited properly,
+ meaning that init() was never called on the PApplet when hosted
+ my some other main() or by other code. For proper use of init(),
+ see the examples in the main description text for PApplet.
+
Returns a path inside the applet folder to save to. Like sketchPath(),
+ but creates any in-between folders so that things save properly.
+
+ All saveXxxx() functions use the path to the sketch folder, rather than
+ its data folder. Once exported, the data folder will be found inside the
+ jar file of the exported application or applet. In this case, it's not
+ possible to save data into the jar file, because it will often be running
+ from a server, or marked in-use if running from a local file system.
+ With this in mind, saving to the data path doesn't make sense anyway.
+ If you know you're running locally, and want to save to the data folder,
+ use saveXxxx("data/blah.dat").
+
Return a full path to an item in the data folder.
+
+ In this method, the data path is defined not as the applet's actual
+ data path, but a folder titled "data" in the sketch's working
+ directory. When running inside the PDE, this will be the sketch's
+ "data" folder. However, when exported (as application or applet),
+ sketch's data folder is exported as part of the applications jar file,
+ and it's not possible to read/write from the jar file in a generic way.
+ If you need to read data from the jar file, you should use createInput().
+
Takes a path and creates any in-between folders if they don't
+ already exist. Useful when trying to save to a subfolder that
+ may not actually exist.
+
+
+
+
+
+
+
+
+
+
+
+createPath
+
+public static void createPath(java.io.File file)
+
+
+
+
+
+
+
+
+
+
+
+sort
+
+public static byte[] sort(byte[] what)
+
+
+
+
+
+
+
+
+
+
+
+sort
+
+public static byte[] sort(byte[] what,
+ int count)
+
+
+
+
+
+
+
+
+
+
+
+sort
+
+public static char[] sort(char[] what)
+
+
+
+
+
+
+
+
+
+
+
+sort
+
+public static char[] sort(char[] what,
+ int count)
+
+
+
+
+
+
+
+
+
+
+
+sort
+
+public static int[] sort(int[] what)
+
+
+
+
+
+
+
+
+
+
+
+sort
+
+public static int[] sort(int[] what,
+ int count)
+
+
+
+
+
+
+
+
+
+
+
+sort
+
+public static float[] sort(float[] what)
+
+
+
+
+
+
+
+
+
+
+
+sort
+
+public static float[] sort(float[] what,
+ int count)
Remove whitespace characters from the beginning and ending
+ of a String. Works like String.trim() but includes the
+ unicode nbsp character as well.
+
Split the provided String at wherever whitespace occurs.
+ Multiple whitespace (extra spaces or tabs or whatever)
+ between items will count as a single break.
+
+ The whitespace characters are "\t\n\r\f", which are the defaults
+ for java.util.StringTokenizer, plus the unicode non-breaking space
+ character, which is found commonly on files created by or used
+ in conjunction with Mac OS X (character 160, or 0x00A0 in hex).
+
Splits a string into pieces, using any of the chars in the
+ String 'delim' as separator characters. For instance,
+ in addition to white space, you might want to treat commas
+ as a separator. The delimeter characters won't appear in
+ the returned String array.
+
Split a string into pieces along a specific character.
+ Most commonly used to break up a String along a space or a tab
+ character.
+
+ This operates differently than the others, where the
+ single delimeter is the only breaking point, and consecutive
+ delimeters will produce an empty string (""). This way,
+ one can split on tab characters, but maintain the column
+ alignments (of say an excel file) where there are empty columns.
+
Split a String on a specific delimiter. Unlike Java's String.split()
+ method, this does not parse the delimiter as a regexp because it's more
+ confusing than necessary, and String.split() is always available for
+ those who want regexp.
+
Match a string with a regular expression, and returns the match as an
+ array. The first index is the matching expression, and array elements
+ [1] and higher represent each of the groups (sequences found in parens).
+
+ This uses multiline matching (Pattern.MULTILINE) and dotall mode
+ (Pattern.DOTALL) by default, so that ^ and $ match the beginning and
+ end of any lines found in the source, and the . operator will also
+ pick up newline characters.
+
Identical to match(), except that it returns an array of all matches in
+ the specified String, rather than just the first.
+
+
+
+
+
+
+
+
+
+
+
+parseBoolean
+
+public static final boolean parseBoolean(int what)
+
+
Convert an integer to a boolean. Because of how Java handles upgrading
+ numbers, this will also cover byte and char (as they will upgrade to
+ an int without any sort of explicit cast).
+
The preprocessor will convert boolean(what) to parseBoolean(what).
+
+
+
+
+
+
+
Returns:
false if 0, true if any other number
+
+
+
+
+
+parseBoolean
+
+public static final boolean parseBoolean(java.lang.String what)
+
+
Convert the string "true" or "false" to a boolean.
+
+
+
+
+
+
+
Returns:
true if 'what' is "true" or "TRUE", false otherwise
+
+
+
+
+
+parseBoolean
+
+public static final boolean[] parseBoolean(byte[] what)
+
+
Convert a byte array to a boolean array. Each element will be
+ evaluated identical to the integer case, where a byte equal
+ to zero will return false, and any other value will return true.
+
+
+
+
+
+
+
Returns:
array of boolean elements
+
+
+
+
+
+parseBoolean
+
+public static final boolean[] parseBoolean(int[] what)
+
+
Convert an int array to a boolean array. An int equal
+ to zero will return false, and any other value will return true.
+
+
+
+
+
+
+
Returns:
array of boolean elements
+
+
+
+
+
+parseBoolean
+
+public static final boolean[] parseBoolean(java.lang.String[] what)
+
+
+
+
+
+
+
+
+
+
+
+parseByte
+
+public static final byte parseByte(boolean what)
+
+
+
+
+
+
+
+
+
+
+
+parseByte
+
+public static final byte parseByte(char what)
+
+
+
+
+
+
+
+
+
+
+
+parseByte
+
+public static final byte parseByte(int what)
+
+
+
+
+
+
+
+
+
+
+
+parseByte
+
+public static final byte parseByte(float what)
+
+
+
+
+
+
+
+
+
+
+
+parseByte
+
+public static final byte[] parseByte(boolean[] what)
+
+
+
+
+
+
+
+
+
+
+
+parseByte
+
+public static final byte[] parseByte(char[] what)
+
+
+
+
+
+
+
+
+
+
+
+parseByte
+
+public static final byte[] parseByte(int[] what)
+
+
+
+
+
+
+
+
+
+
+
+parseByte
+
+public static final byte[] parseByte(float[] what)
+
+
+
+
+
+
+
+
+
+
+
+parseChar
+
+public static final char parseChar(byte what)
+
+
+
+
+
+
+
+
+
+
+
+parseChar
+
+public static final char parseChar(int what)
+
+
+
+
+
+
+
+
+
+
+
+parseChar
+
+public static final char[] parseChar(byte[] what)
+
+
+
+
+
+
+
+
+
+
+
+parseChar
+
+public static final char[] parseChar(int[] what)
+
+
+
+
+
+
+
+
+
+
+
+parseInt
+
+public static final int parseInt(boolean what)
+
+
+
+
+
+
+
+
+
+
+
+parseInt
+
+public static final int parseInt(byte what)
+
+
Note that parseInt() will un-sign a signed byte value.
+
+
+
+
+
+
+
+
+
+
+
+parseInt
+
+public static final int parseInt(char what)
+
+
Note that parseInt('5') is unlike String in the sense that it
+ won't return 5, but the ascii value. This is because ((int) someChar)
+ returns the ascii value, and parseInt() is just longhand for the cast.
+
+
+
+
+
+
+
+
+
+
+
+parseInt
+
+public static final int parseInt(float what)
+
+
Same as floor(), or an (int) cast.
+
+
+
+
+
+
+
+
+
+
+
+parseInt
+
+public static final int parseInt(java.lang.String what)
+
+
Parse a String into an int value. Returns 0 if the value is bad.
+
+
+
+
+
+
+
+
+
+
+
+parseInt
+
+public static final int parseInt(java.lang.String what,
+ int otherwise)
+
+
Parse a String to an int, and provide an alternate value that
+ should be used when the number is invalid.
+
+
+
+
+
+
+
+
+
+
+
+parseInt
+
+public static final int[] parseInt(boolean[] what)
Make an array of int elements from an array of String objects.
+ If the String can't be parsed as a number, it will be set to zero.
+
+ String s[] = { "1", "300", "44" };
+ int numbers[] = parseInt(s);
+
+ numbers will contain { 1, 300, 44 }
+
+
+
+
+
+
+
+
+
+
+
+parseInt
+
+public static int[] parseInt(java.lang.String[] what,
+ int missing)
+
+
Make an array of int elements from an array of String objects.
+ If the String can't be parsed as a number, its entry in the
+ array will be set to the value of the "missing" parameter.
+
+ String s[] = { "1", "300", "apple", "44" };
+ int numbers[] = parseInt(s, 9999);
+
+ numbers will contain { 1, 300, 9999, 44 }
+
+
+
+
+
+
+
+
+
+
+
+parseFloat
+
+public static final float parseFloat(int what)
+
+
Convert an int to a float value. Also handles bytes because of
+ Java's rules for upgrading values.
+
+
+
+
+
+
+
+
+
+
+
+parseFloat
+
+public static final float parseFloat(java.lang.String what)
+
+
+
+
+
+
+
+
+
+
+
+parseFloat
+
+public static final float parseFloat(java.lang.String what,
+ float otherwise)
+
+
+
+
+
+
+
+
+
+
+
+parseByte
+
+public static final float[] parseByte(byte[] what)
+
+
+
+
+
+
+
+
+
+
+
+parseFloat
+
+public static final float[] parseFloat(int[] what)
+
+
+
+
+
+
+
+
+
+
+
+parseFloat
+
+public static final float[] parseFloat(java.lang.String[] what)
+
+
+
+
+
+
+
+
+
+
+
+parseFloat
+
+public static final float[] parseFloat(java.lang.String[] what,
+ float missing)
+
+
+
+
+
+
+
+
+
+
+
+str
+
+public static final java.lang.String str(boolean x)
+
+
+
+
+
+
+
+
+
+
+
+str
+
+public static final java.lang.String str(byte x)
+
+
+
+
+
+
+
+
+
+
+
+str
+
+public static final java.lang.String str(char x)
+
+
+
+
+
+
+
+
+
+
+
+str
+
+public static final java.lang.String str(int x)
+
+
+
+
+
+
+
+
+
+
+
+str
+
+public static final java.lang.String str(float x)
+
+
+
+
+
+
+
+
+
+
+
+str
+
+public static final java.lang.String[] str(boolean[] x)
+
+
+
+
+
+
+
+
+
+
+
+str
+
+public static final java.lang.String[] str(byte[] x)
+
+
+
+
+
+
+
+
+
+
+
+str
+
+public static final java.lang.String[] str(char[] x)
+
+
+
+
+
+
+
+
+
+
+
+str
+
+public static final java.lang.String[] str(int[] x)
+
+
+
+
+
+
+
+
+
+
+
+str
+
+public static final java.lang.String[] str(float[] x)
+
+
+
+
+
+
+
+
+
+
+
+nf
+
+public static java.lang.String[] nf(int[] num,
+ int digits)
+
+
+
+
+
+
+
+
+
+
+
+nf
+
+public static java.lang.String nf(int num,
+ int digits)
+
+
+
+
+
+
+
+
+
+
+
+nfc
+
+public static java.lang.String[] nfc(int[] num)
+
+
+
+
+
+
+
+
+
+
+
+nfc
+
+public static java.lang.String nfc(int num)
+
+
+
+
+
+
+
+
+
+
+
+nfs
+
+public static java.lang.String nfs(int num,
+ int digits)
+
+
number format signed (or space)
+ Formats a number but leaves a blank space in the front
+ when it's positive so that it can be properly aligned with
+ numbers that have a negative sign in front of them.
+
+
+
+
+
+
+
+
+
+
+
+nfs
+
+public static java.lang.String[] nfs(int[] num,
+ int digits)
+
+
+
+
+
+
+
+
+
+
+
+nfp
+
+public static java.lang.String nfp(int num,
+ int digits)
+
+
number format positive (or plus)
+ Formats a number, always placing a - or + sign
+ in the front when it's negative or positive.
+
+
+
+
+
+
+
+
+
+
+
+nfp
+
+public static java.lang.String[] nfp(int[] num,
+ int digits)
+
+
+
+
+
+
+
+
+
+
+
+nf
+
+public static java.lang.String[] nf(float[] num,
+ int left,
+ int right)
+
+
+
+
+
+
+
+
+
+
+
+nf
+
+public static java.lang.String nf(float num,
+ int left,
+ int right)
+
+
+
+
+
+
+
+
+
+
+
+nfc
+
+public static java.lang.String[] nfc(float[] num,
+ int right)
+
+
+
+
+
+
+
+
+
+
+
+nfc
+
+public static java.lang.String nfc(float num,
+ int right)
+
+
+
+
+
+
+
+
+
+
+
+nfs
+
+public static java.lang.String[] nfs(float[] num,
+ int left,
+ int right)
+
+
Number formatter that takes into account whether the number
+ has a sign (positive, negative, etc) in front of it.
+
+
+
+
+
+
+
+
+
+
+
+nfs
+
+public static java.lang.String nfs(float num,
+ int left,
+ int right)
+
+
+
+
+
+
+
+
+
+
+
+nfp
+
+public static java.lang.String[] nfp(float[] num,
+ int left,
+ int right)
+
+
+
+
+
+
+
+
+
+
+
+nfp
+
+public static java.lang.String nfp(float num,
+ int left,
+ int right)
+
+
+
+
+
+
+
+
+
+
+
+hex
+
+public static final java.lang.String hex(byte what)
+
+
+
+
+
+
+
+
+
+
+
+hex
+
+public static final java.lang.String hex(char what)
+
+
+
+
+
+
+
+
+
+
+
+hex
+
+public static final java.lang.String hex(int what)
+
+
+
+
+
+
+
+
+
+
+
+hex
+
+public static final java.lang.String hex(int what,
+ int digits)
+
+
+
+
+
+
+
+
+
+
+
+unhex
+
+public static final int unhex(java.lang.String what)
+
+
+
+
+
+
+
+
+
+
+
+binary
+
+public static final java.lang.String binary(byte what)
+
+
Returns a String that contains the binary value of a byte.
+ The returned value will always have 8 digits.
+
+
+
+
+
+
+
+
+
+
+
+binary
+
+public static final java.lang.String binary(char what)
+
+
Returns a String that contains the binary value of a char.
+ The returned value will always have 16 digits because chars
+ are two bytes long.
+
+
+
+
+
+
+
+
+
+
+
+binary
+
+public static final java.lang.String binary(int what)
+
+
Returns a String that contains the binary value of an int.
+ The length depends on the size of the number itself.
+ An int can be up to 32 binary digits, but that seems like
+ overkill for almost any situation, so this function just
+ auto-size. If you want a specific number of digits (like all 32)
+ use binary(int what, int digits) to specify how many digits.
+
+
+
+
+
+
+
+
+
+
+
+binary
+
+public static final java.lang.String binary(int what,
+ int digits)
+
+
Returns a String that contains the binary value of an int.
+ The digits parameter determines how many digits will be used.
+
+
+
+
+
+
+
+
+
+
+
+unbinary
+
+public static final int unbinary(java.lang.String what)
+
+
Unpack a binary String into an int.
+ i.e. unbinary("00001000") would return 8.
+
+
+
+
+
+
+
+
+
+
+
+color
+
+public final int color(int gray)
+
+
+
+
+
+
+
+
+
+
+
+color
+
+public final int color(float fgray)
+
+
+
+
+
+
+
+
+
+
+
+color
+
+public final int color(int gray,
+ int alpha)
+
+
As of 0116 this also takes color(#FF8800, alpha)
+
+
+
+
+
+
+
+
+
+
+
+color
+
+public final int color(float fgray,
+ float falpha)
+
+
+
+
+
+
+
+
+
+
+
+color
+
+public final int color(int x,
+ int y,
+ int z)
+
+
+
+
+
+
+
+
+
+
+
+color
+
+public final int color(float x,
+ float y,
+ float z)
+
+
+
+
+
+
+
+
+
+
+
+color
+
+public final int color(int x,
+ int y,
+ int z,
+ int a)
+
+
+
+
+
+
+
+
+
+
+
+color
+
+public final int color(float x,
+ float y,
+ float z,
+ float a)
+
+
+
+
+
+
+
+
+
+
+
+setupExternalMessages
+
+public void setupExternalMessages()
+
+
Set this sketch to communicate its state back to the PDE.
+
+ This uses the stderr stream to write positions of the window
+ (so that it will be saved by the PDE for the next run) and
+ notify on quit. See more notes in the Worker class.
+
+
+
+
+
+
+
+
+
+
+
+setupFrameResizeListener
+
+public void setupFrameResizeListener()
+
+
Set up a listener that will fire proper component resize events
+ in cases where frame.setResizable(true) is called.
+
+
+
+
+
+
+
+
+
+
+
+main
+
+public static void main(java.lang.String[] args)
+
+
main() method for running this class from the command line.
+
+ The options shown here are not yet finalized and will be
+ changing over the next several releases.
+
+ The simplest way to turn and applet into an application is to
+ add the following code to your program:
+
+ This will properly launch your applet from a double-clickable
+ .jar or from the command line.
+
+ Parameters useful for launching or also used by the PDE:
+
+ --location=x,y upper-lefthand corner of where the applet
+ should appear on screen. if not used,
+ the default is to center on the main screen.
+
+ --present put the applet into full screen presentation
+ mode. requires java 1.4 or later.
+
+ --exclusive use full screen exclusive mode when presenting.
+ disables new windows or interaction with other
+ monitors, this is like a "game" mode.
+
+ --hide-stop use to hide the stop button in situations where
+ you don't want to allow users to exit. also
+ see the FAQ on information for capturing the ESC
+ key when running in presentation mode.
+
+ --stop-color=#xxxxxx color of the 'stop' text used to quit an
+ sketch when it's in present mode.
+
+ --bgcolor=#xxxxxx background color of the window.
+
+ --sketch-path location of where to save files from functions
+ like saveStrings() or saveFrame(). defaults to
+ the folder that the java application was
+ launched from, which means if this isn't set by
+ the pde, everything goes into the same folder
+ as processing.exe.
+
+ --display=n set what display should be used by this applet.
+ displays are numbered starting from 1.
+
+ Parameters used by Processing when running via the PDE
+
+ --external set when the applet is being used by the PDE
+
+ --editor-location=x,y position of the upper-lefthand corner of the
+ editor window, for placement of applet window
+
Begin recording raw shape data to a renderer of the specified type,
+ using the width and height of the main drawing surface.
+
+ If hashmarks (###) are found in the filename, they'll be replaced
+ by the current frame number (frameCount).
+
Begin recording raw shape data to the specified renderer.
+
+ This simply echoes to g.beginRaw(), but since is placed here (rather than
+ generated by preproc.pl) for clarity and so that it doesn't echo the
+ command should beginRecord() be in use.
+
+
+
+
+
+
+
+
+
+
+
+endRaw
+
+public void endRaw()
+
+
Stop recording raw shape data to the specified renderer.
+
+ This simply echoes to g.beginRaw(), but since is placed here (rather than
+ generated by preproc.pl) for clarity and so that it doesn't echo the
+ command should beginRecord() be in use.
+
+
+
+
+
+
+
+
+
+
+
+loadPixels
+
+public void loadPixels()
+
+
Override the g.pixels[] function to set the pixels[] array
+ that's part of the PApplet object. Allows the use of
+ pixels[] in the code, rather than g.pixels[].
+
+
+
+
+
+
+
+
+
+
+
+updatePixels
+
+public void updatePixels()
+
+
+
+
+
+
+
+
+
+
+
+updatePixels
+
+public void updatePixels(int x1,
+ int y1,
+ int x2,
+ int y2)
+ An attempt is made to keep the constants as short/non-verbose
+ as possible. For instance, the constant is TIFF instead of
+ FILE_TYPE_TIFF. We'll do this as long as we can get away with it.
+
MAX_FLOAT
+
+
+ Same as Float.MAX_VALUE, but included for parity with MIN_VALUE,
+ and to avoid teaching static methods on the first day.
+
+
+
+static int
+
MAX_INT
+
+
+ Largest possible (positive) integer value
+
+
+
+static float
+
MIN_FLOAT
+
+
+ Note that Float.MIN_VALUE is the smallest positive value
+ for a floating point number, not actually the minimum (negative) value
+ for a float.
+
+
+
+static int
+
MIN_INT
+
+
+ Smallest possible (negative) integer value
Note that Float.MIN_VALUE is the smallest positive value
+ for a floating point number, not actually the minimum (negative) value
+ for a float. This constant equals 0xFF7FFFFF, the smallest (farthest
+ negative) value a float can have before it hits NaN.
+
textMode(MODEL) is the default, meaning that characters
+ will be affected by transformations like any other shapes.
+
+ Changed value in 0093 to not interfere with LEFT, CENTER, and RIGHT.
+
textMode(SHAPE) draws text using the the glyph outlines of
+ individual characters rather than as textures. If the outlines are
+ not available, then textMode(SHAPE) will be ignored and textMode(MODEL)
+ will be used instead. For this reason, be sure to call textMode()
+ after calling textFont().
+
+ Currently, textMode(SHAPE) is only supported by OPENGL mode.
+ It also requires Java 1.2 or higher (OPENGL requires 1.4 anyway)
+
+Grayscale bitmap font class used by Processing.
+
+ Awful (and by that, I mean awesome) ascii (non)art for how this works:
+
+ |
+ | height is the full used height of the image
+ |
+ | ..XX.. }
+ | ..XX.. }
+ | ...... }
+ | XXXX.. } topExtent (top y is baseline - topExtent)
+ | ..XX.. }
+ | ..XX.. } dotted areas are where the image data
+ | ..XX.. } is actually located for the character
+ +---XXXXXX---- } (it extends to the right and down
+ | for power of two texture sizes)
+ ^^^^ leftExtent (amount to move over before drawing the image
+
+ ^^^^^^^^^^^^^^ setWidth (width displaced by char)
+
Name of the font as seen by Java when it was created.
+ If the font is available, the native version will be used.
+
+
+
+
+
+
+
+psname
+
+public java.lang.String psname
+
+
Postscript name of the font that this bitmap was created from.
+
+
+
+
+
+
+
+size
+
+public int size
+
+
"natural" size of the font (most often 48)
+
+
+
+
+
+
+
+smooth
+
+public boolean smooth
+
+
true if smoothing was enabled for this font, used for native impl
+
+
+
+
+
+
+
+mbox2
+
+public int mbox2
+
+
next power of 2 over the max image size (usually 64)
+
+
+
+
+
+
+
+twidth
+
+public int twidth
+
+
texture width, same as mbox2, but reserved for future use
+
+
+
+
+
+
+
+theight
+
+public int theight
+
+
texture height, same as mbox2, but reserved for future use
+
+
+
+
+
+
+
+value
+
+public int[] value
+
+
+
+
+
+
+
+height
+
+public int[] height
+
+
+
+
+
+
+
+width
+
+public int[] width
+
+
+
+
+
+
+
+setWidth
+
+public int[] setWidth
+
+
+
+
+
+
+
+topExtent
+
+public int[] topExtent
+
+
+
+
+
+
+
+leftExtent
+
+public int[] leftExtent
+
+
+
+
+
+
+
+ascent
+
+public int ascent
+
+
+
+
+
+
+
+descent
+
+public int descent
+
+
+
+
+
+
+
+DEFAULT_CHARSET
+
+public static char[] DEFAULT_CHARSET
+
+
The default Processing character set.
+
+ This is the union of the Mac Roman and Windows ANSI (CP1250)
+ character sets. ISO 8859-1 Latin 1 is Unicode characters 0x80 -> 0xFF,
+ and would seem a good standard, but in practice, most P5 users would
+ rather have characters that they expect from their platform's fonts.
+
+ This is more of an interim solution until a much better
+ font solution can be determined. (i.e. create fonts on
+ the fly from some sort of vector format).
+
+ This is used by the Create Font tool, or whatever anyone else dreams
+ up for messing with fonts themselves.
+
+ It is assumed that the calling class will handle closing
+ the stream when finished.
+
+
+
+
+
+
+
Throws:
+
java.io.IOException
+
+
+
+
+
+index
+
+public int index(char c)
+
+
Get index for the char (convert from unicode to bagel charset).
+
+
+
+
+
+
+
Returns:
index into arrays or -1 if not found
+
+
+
+
+
+kern
+
+public float kern(char a,
+ char b)
+
+
Currently un-implemented for .vlw fonts,
+ but honored for layout in case subclasses use it.
+
+
+
+
+
+
+
+
+
+
+
+ascent
+
+public float ascent()
+
+
Returns the ascent of this font from the baseline.
+ The value is based on a font of size 1.
+
+
+
+
+
+
+
+
+
+
+
+descent
+
+public float descent()
+
+
Returns how far this font descends from the baseline.
+ The value is based on a font size of 1.
+
+
+
+
+
+
+
+
+
+
+
+width
+
+public float width(char c)
+
+
Width of this character for a font of size 1.
+
+
+
+
+
+
+
+
+
+
+
+list
+
+public static java.lang.String[] list()
+
+
Get a list of the fonts installed on the system that can be used
+ by Java. Not all fonts can be used in Java, in fact it's mostly
+ only TrueType fonts. OpenType fonts with CFF data such as Adobe's
+ OpenType fonts seem to have trouble (even though they're sort of
+ TrueType fonts as well, or may have a .ttf extension). Regular
+ PostScript fonts seem to work OK, however.
+
+ Not recommended for use in applets, but this is implemented
+ in PFont because the Java methods to access this information
+ have changed between 1.1 and 1.4, and the 1.4 method is
+ typical of the sort of undergraduate-level over-abstraction
+ that the seems to have made its way into the Java API after 1.1.
+
Starting with Java 1.5, Apple broke the ability to specify most fonts.
+ This has been filed as bug #4769141 at bugreporter.apple.com. More info at
+ Bug 407.
+
+Main graphics and rendering context, as well as the base API implementation.
+
+
Subclassing and initializing PGraphics objects
+ Starting in release 0149, subclasses of PGraphics are handled differently.
+ The constructor for subclasses takes no parameters, instead a series of
+ functions are called by the hosting PApplet to specify its attributes.
+
+
setParent(PApplet) - is called to specify the parent PApplet.
+
setPrimary(boolean) - called with true if this PGraphics will be the
+ primary drawing surface used by the sketch, or false if not.
+
setPath(String) - called when the renderer needs a filename or output
+ path, such as with the PDF or DXF renderers.
+
setSize(int, int) - this is called last, at which point it's safe for
+ the renderer to complete its initialization routine.
+
+ The functions were broken out because of the growing number of parameters
+ such as these that might be used by a renderer, yet with the exception of
+ setSize(), it's not clear which will be necessary. So while the size could
+ be passed in to the constructor instead of a setSize() function, a function
+ would still be needed that would notify the renderer that it was time to
+ finish its initialization. Thus, setSize() simply does both.
+
+
Know your rights: public vs. private methods
+ Methods that are protected are often subclassed by other renderers, however
+ they are not set 'public' because they shouldn't be part of the user-facing
+ public API accessible from PApplet. That is, we don't want sketches calling
+ textModeCheck() or vertexTexture() directly.
+
+
Handling warnings and exceptions
+ Methods that are unavailable generally show a warning, unless their lack of
+ availability will soon cause another exception. For instance, if a method
+ like getMatrix() returns null because it is unavailable, an exception will
+ be thrown stating that the method is unavailable, rather than waiting for
+ the NullPointerException that will occur when the sketch tries to use that
+ method. As of release 0149, warnings will only be shown once, and exceptions
+ have been changed to warnings where possible.
+
+
Using xxxxImpl() for subclassing smoothness
+ The xxxImpl() methods are generally renderer-specific handling for some
+ subset if tasks for a particular function (vague enough for you?) For
+ instance, imageImpl() handles drawing an image whose x/y/w/h and u/v coords
+ have been specified, and screen placement (independent of imageMode) has
+ been determined. There's no point in all renderers implementing the
+ if (imageMode == BLAH) placement/sizing logic, so that's handled
+ by PGraphics, which then calls imageImpl() once all that is figured out.
+
+
His brother PImage
+ PGraphics subclasses PImage so that it can be drawn and manipulated in a
+ similar fashion. As such, many methods are inherited from PGraphics,
+ though many are unavailable: for instance, resize() is not likely to be
+ implemented; the same goes for mask(), depending on the situation.
+
+
What's in PGraphics, what ain't
+ For the benefit of subclasses, as much as possible has been placed inside
+ PGraphics. For instance, bezier interpolation code and implementations of
+ the strokeCap() method (that simply sets the strokeCap variable) are
+ handled here. Features that will vary widely between renderers are located
+ inside the subclasses themselves. For instance, all matrix handling code
+ is per-renderer: Java 2D uses its own AffineTransform, P2D uses a PMatrix2D,
+ and PGraphics3D needs to keep continually update forward and reverse
+ transformations. A proper (future) OpenGL implementation will have all its
+ matrix madness handled by the card. Lighting also falls under this
+ category, however the base material property settings (emissive, specular,
+ et al.) are handled in PGraphics because they use the standard colorMode()
+ logic. Subclasses should override methods like emissiveFromCalc(), which
+ is a point where a valid color has been defined internally, and can be
+ applied in some manner based on the calcXxxx values.
+
+
What's in the PGraphics documentation, what ain't
+ Some things are noted here, some things are not. For public API, always
+ refer to the reference
+ on Processing.org for proper explanations. No attempt has been made to
+ keep the javadoc up to date or complete. It's an enormous task for
+ which we simply do not have the time. That is, it's not something that
+ to be done once—it's a matter of keeping the multiple references
+ synchronized (to say nothing of the translation issues), while targeting
+ them for their separate audiences. Ouch.
+
textureImage
+
+
+ Current image being used as a texture
+
+
+
+ int
+
textureMode
+
+
+ Sets whether texture coordinates passed to
+ vertex() calls will be based on coordinates that are
+ based on the IMAGE or NORMALIZED.
+
+
+
+ float
+
textureU
+
+
+ Current horizontal coordinate for texture, will always
+ be between 0 and 1, even if using textureMode(IMAGE).
+
+
+
+ float
+
textureV
+
+
+ Current vertical coordinate for texture, see above.
arc(float a,
+ float b,
+ float c,
+ float d,
+ float start,
+ float stop)
+
+
+ Identical parameters and placement to ellipse,
+ but draws only an arc of that ellipse.
+
+
+
+ void
+
background(float gray)
+
+
+ Set the background to a grayscale value, based on the
+ current colorMode.
+
+
+
+ void
+
background(float gray,
+ float alpha)
+
+
+ See notes about alpha in background(x, y, z, a).
+
+
+
+ void
+
background(float x,
+ float y,
+ float z)
+
+
+ Set the background to an r, g, b or h, s, b value,
+ based on the current colorMode.
+
+
+
+ void
+
background(float x,
+ float y,
+ float z,
+ float a)
+
+
+ Clear the background with a color that includes an alpha value.
+
+
+
+ void
+
background(int rgb)
+
+
+ Set the background to a gray or ARGB color.
+
+
+
+ void
+
background(int rgb,
+ float alpha)
+
+
+ See notes about alpha in background(x, y, z, a).
+
+
+
+ void
+
background(PImage image)
+
+
+ Takes an RGB or ARGB image and sets it as the background.
scale(float sx,
+ float sy)
+
+
+ Scale in X and Y.
+
+
+
+ void
+
scale(float x,
+ float y,
+ float z)
+
+
+ Scale in X, Y, and Z.
+
+
+
+ float
+
screenX(float x,
+ float y)
+
+
+ Given an x and y coordinate, returns the x position of where
+ that point would be placed on screen, once affected by translate(),
+ scale(), or any other transformations.
+
+
+
+ float
+
screenX(float x,
+ float y,
+ float z)
+
+
+ Maps a three dimensional point to its placement on-screen.
+
+
+
+ float
+
screenY(float x,
+ float y)
+
+
+ Given an x and y coordinate, returns the y position of where
+ that point would be placed on screen, once affected by translate(),
+ scale(), or any other transformations.
+
+
+
+ float
+
screenY(float x,
+ float y,
+ float z)
+
+
+ Maps a three dimensional point to its placement on-screen.
+
+
+
+ float
+
screenZ(float x,
+ float y,
+ float z)
+
+
+ Maps a three dimensional point to its placement on-screen.
+
+
+
+ void
+
setMatrix(PMatrix source)
+
+
+ Set the current transformation matrix to the contents of another.
+
+
+
+ void
+
setMatrix(PMatrix2D source)
+
+
+ Set the current transformation to the contents of the specified source.
+
+
+
+ void
+
setMatrix(PMatrix3D source)
+
+
+ Set the current transformation to the contents of the specified source.
textFont(PFont which,
+ float size)
+
+
+ Useful function to set the font and size at the same time.
+
+
+
+ void
+
textLeading(float leading)
+
+
+ Set the text leading to a specific value.
+
+
+
+ void
+
textMode(int mode)
+
+
+ Sets the text rendering/placement to be either SCREEN (direct
+ to the screen, exact coordinates, only use the font's original size)
+ or MODEL (the default, where text is manipulated by translate() and
+ can have a textSize).
+
+
+
+ void
+
textSize(float size)
+
+
+ Sets the text size, also resets the value for the leading.
+
+
+
+ void
+
texture(PImage image)
+
+
+ Set texture image for current shape.
+
+
+
+ void
+
textureMode(int mode)
+
+
+ Set texture mode to either to use coordinates based on the IMAGE
+ (more intuitive for new users) or NORMALIZED (better for advanced chaps)
Max value for green (or saturation) set by colorMode
+
+
+
+
+
+
+
+colorModeZ
+
+public float colorModeZ
+
+
Max value for blue (or value) set by colorMode
+
+
+
+
+
+
+
+colorModeA
+
+public float colorModeA
+
+
Max value for alpha set by colorMode
+
+
+
+
+
+
+
+tint
+
+public boolean tint
+
+
True if tint() is enabled (read-only).
+
+ Using tint/tintColor seems a better option for naming than
+ tintEnabled/tint because the latter seems ugly, even though
+ g.tint as the actual color seems a little more intuitive,
+ it's just that g.tintEnabled is even more unintuitive.
+ Same goes for fill and stroke, et al.
+
+
+
+
+
+
+
+tintColor
+
+public int tintColor
+
+
tint that was last set (read-only)
+
+
+
+
+
+
+
+fill
+
+public boolean fill
+
+
true if fill() is enabled, (read-only)
+
+
+
+
+
+
+
+fillColor
+
+public int fillColor
+
+
fill that was last set (read-only)
+
+
+
+
+
+
+
+stroke
+
+public boolean stroke
+
+
true if stroke() is enabled, (read-only)
+
+
+
+
+
+
+
+strokeColor
+
+public int strokeColor
+
+
stroke that was last set (read-only)
+
+
+
+
+
+
+
+strokeWeight
+
+public float strokeWeight
+
+
Last value set by strokeWeight() (read-only). This has a default
+ setting, rather than fighting with renderers about whether that
+ renderer supports thick lines.
+
+
+
+
+
+
+
+strokeJoin
+
+public int strokeJoin
+
+
Set by strokeJoin() (read-only). This has a default setting
+ so that strokeJoin() need not be called by defaults,
+ because subclasses may not implement it (i.e. PGraphicsGL)
+
+
+
+
+
+
+
+strokeCap
+
+public int strokeCap
+
+
Set by strokeCap() (read-only). This has a default setting
+ so that strokeCap() need not be called by defaults,
+ because subclasses may not implement it (i.e. PGraphicsGL)
+
Last background color that was set, zero if an image
+
+
+
+
+
+
+
+image
+
+public java.awt.Image image
+
+
Java AWT Image object associated with this renderer. For P2D and P3D,
+ this will be associated with their MemoryImageSource. For PGraphicsJava2D,
+ it will be the offscreen drawing buffer.
+
+
+
+
+
+
+
+bezierDetail
+
+public int bezierDetail
+
+
+
+
+
+
+
+curveTightness
+
+public float curveTightness
+
+
+
+
+
+
+
+edge
+
+public boolean edge
+
+
+
+
+
+
+
+normalX
+
+public float normalX
+
+
Current normal vector.
+
+
+
+
+
+
+
+normalY
+
+public float normalY
+
+
Current normal vector.
+
+
+
+
+
+
+
+normalZ
+
+public float normalZ
+
+
Current normal vector.
+
+
+
+
+
+
+
+textureMode
+
+public int textureMode
+
+
Sets whether texture coordinates passed to
+ vertex() calls will be based on coordinates that are
+ based on the IMAGE or NORMALIZED.
+
+
+
+
+
+
+
+textureU
+
+public float textureU
+
+
Current horizontal coordinate for texture, will always
+ be between 0 and 1, even if using textureMode(IMAGE).
+
+
+
+
+
+
+
+textureV
+
+public float textureV
+
+
Current vertical coordinate for texture, see above.
+
Constructor for the PGraphics object. Use this to ensure that
+ the defaults get set properly. In a subclass, use this(w, h)
+ as the first line of a subclass' constructor to properly set
+ the internal fields and defaults.
+
Set (or unset) this as the main drawing surface. Meaning that it can
+ safely be set to opaque (and given a default gray background), or anything
+ else that goes along with that.
+
+
+
+
+
+
+
+
+
+
+
+setPath
+
+public void setPath(java.lang.String path)
+
+
+
+
+
+
+
+
+
+
+
+setSize
+
+public void setSize(int w,
+ int h)
+
+
The final step in setting up a renderer, set its size of this renderer.
+ This was formerly handled by the constructor, but instead it's been broken
+ out so that setParent/setPrimary/setPath can be handled differently.
+
+ Important that this is ignored by preproc.pl because otherwise it will
+ override setSize() in PApplet/Applet/Component, which will 1) not call
+ super.setSize(), and 2) will cause the renderer to be resized from the
+ event thread (EDT), causing a nasty crash as it collides with the
+ animation thread.
+
+
+
+
+
+
+
+
+
+
+
+dispose
+
+public void dispose()
+
+
Handle any takedown for this graphics context.
+
+ This is called when a sketch is shut down and this renderer was
+ specified using the size() command, or inside endRecord() and
+ endRaw(), in order to shut things off.
+
+
+
+
+
+
+
+
+
+
+
+canDraw
+
+public boolean canDraw()
+
+
Some renderers have requirements re: when they are ready to draw.
+
+
+
+
+
+
+
+
+
+
+
+beginDraw
+
+public void beginDraw()
+
+
Prepares the PGraphics for drawing.
+
+ When creating your own PGraphics, you should call this before
+ drawing anything.
+
+
+
+
+
+
+
+
+
+
+
+endDraw
+
+public void endDraw()
+
+
This will finalize rendering so that it can be shown on-screen.
+
+ When creating your own PGraphics, you should call this when
+ you're finished drawing.
+
+
+
+
+
+
+
+
+
+
+
+flush
+
+public void flush()
+
+
+
+
+
+
+
+
+
+
+
+hint
+
+public void hint(int which)
+
+
Enable a hint option.
+
+ For the most part, hints are temporary api quirks,
+ for which a proper api hasn't been properly worked out.
+ for instance SMOOTH_IMAGES existed because smooth()
+ wasn't yet implemented, but it will soon go away.
+
+ They also exist for obscure features in the graphics
+ engine, like enabling/disabling single pixel lines
+ that ignore the zbuffer, the way they do in alphabot.
+
+ Current hint options:
+
+
DISABLE_DEPTH_TEST -
+ turns off the z-buffer in the P3D or OPENGL renderers.
+
+
+
+
+
+
+
+
+
+
+
+
+beginShape
+
+public void beginShape()
+
+
Start a new shape of type POLYGON
+
+
+
+
+
+
+
+
+
+
+
+beginShape
+
+public void beginShape(int kind)
+
+
Start a new shape.
+
+ Differences between beginShape() and line() and point() methods.
+
+ beginShape() is intended to be more flexible at the expense of being
+ a little more complicated to use. it handles more complicated shapes
+ that can consist of many connected lines (so you get joins) or lines
+ mixed with curves.
+
+ The line() and point() command are for the far more common cases
+ (particularly for our audience) that simply need to draw a line
+ or a point on the screen.
+
+ From the code side of things, line() may or may not call beginShape()
+ to do the drawing. In the beta code, they do, but in the alpha code,
+ they did not. they might be implemented one way or the other depending
+ on tradeoffs of runtime efficiency vs. implementation efficiency &mdash
+ meaning the speed that things run at vs. the speed it takes me to write
+ the code and maintain it. for beta, the latter is most important so
+ that's how things are implemented.
+
+
+
+
+
+
+
+
+
+
+
+edge
+
+public void edge(boolean edge)
+
+
Sets whether the upcoming vertex is part of an edge.
+ Equivalent to glEdgeFlag(), for people familiar with OpenGL.
+
Sets the current normal vector. Only applies with 3D rendering
+ and inside a beginShape/endShape block.
+
+ This is for drawing three dimensional shapes and surfaces,
+ allowing you to specify a vector perpendicular to the surface
+ of the shape, which determines how lighting affects it.
+
+ For the most part, PGraphics3D will attempt to automatically
+ assign normals to shapes, but since that's imperfect,
+ this is a better option when you want more control.
+
+ For people familiar with OpenGL, this function is basically
+ identical to glNormal3f().
+
+
+
+
+
+
+
+
+
+
+
+textureMode
+
+public void textureMode(int mode)
+
+
Set texture mode to either to use coordinates based on the IMAGE
+ (more intuitive for new users) or NORMALIZED (better for advanced chaps)
+
Identical parameters and placement to ellipse,
+ but draws only an arc of that ellipse.
+
+ start and stop are always radians because angleMode() was goofy.
+ ellipseMode() sets the placement.
+
+ also tries to be smart about start < stop.
+
+
+
+
+
+
+
+
+
+
+
+box
+
+public void box(float size)
+
+
+
+
+
+
+
+
+
+
+
+box
+
+public void box(float w,
+ float h,
+ float d)
+
+
+
+
+
+
+
+
+
+
+
+sphereDetail
+
+public void sphereDetail(int res)
+
+
+
+
+
+
+
+
+
+
+
+sphereDetail
+
+public void sphereDetail(int ures,
+ int vres)
+
+
Set the detail level for approximating a sphere. The ures and vres params
+ control the horizontal and vertical resolution.
+
+ Code for sphereDetail() submitted by toxi [031031].
+ Code for enhanced u/v version from davbol [080801].
+
+
+
+
+
+
+
+
+
+
+
+sphere
+
+public void sphere(float r)
+
+
Draw a sphere with radius r centered at coordinate 0, 0, 0.
+
+ Implementation notes:
+
+ cache all the points of the sphere in a static array
+ top and bottom are just a bunch of triangles that land
+ in the center point
+
+ sphere is a series of concentric circles who radii vary
+ along the shape, based on, er.. cos or something
+
+ [toxi 031031] new sphere code. removed all multiplies with
+ radius, as scale() will take care of that anyway
+
+ [toxi 031223] updated sphere code (removed modulos)
+ and introduced sphereAt(x,y,z,r)
+ to avoid additional translate()'s on the user/sketch side
+
+ [davbol 080801] now using separate sphereDetailU/V
+
Evalutes quadratic bezier at point t for points a, b, c, d.
+ t varies between 0 and 1, and a and d are the on curve points,
+ b and c are the control points. this can be done once with the
+ x coordinates and a second time with the y coordinates to get
+ the location of a bezier curve at t.
+
+ For instance, to convert the following example:
+ stroke(255, 102, 0);
+ line(85, 20, 10, 10);
+ line(90, 90, 15, 80);
+ stroke(0, 0, 0);
+ bezier(85, 20, 10, 10, 90, 90, 15, 80);
+
+ // draw it in gray, using 10 steps instead of the default 20
+ // this is a slower way to do it, but useful if you need
+ // to do things with the coordinates at each step
+ stroke(128);
+ beginShape(LINE_STRIP);
+ for (int i = 0; i <= 10; i++) {
+ float t = i / 10.0f;
+ float x = bezierPoint(85, 10, 90, 15, t);
+ float y = bezierPoint(20, 10, 90, 80, t);
+ vertex(x, y);
+ }
+ endShape();
Draw a cubic bezier curve. The first and last points are
+ the on-curve points. The middle two are the 'control' points,
+ or 'handles' in an application like Illustrator.
+
+ As of 0070, this function no longer doubles the first and
+ last points. The curves are a bit more boring, but it's more
+ mathematically correct, and properly mirrored in curvePoint().
+
+public void image(PImage image,
+ float a,
+ float b,
+ float c,
+ float d,
+ int u1,
+ int v1,
+ int u2,
+ int v2)
+
+
Draw an image(), also specifying u/v coordinates.
+ In this method, the u, v coordinates are always based on image space
+ location, regardless of the current textureMode().
+
+
+
+
+
+
+
+
+
+
+
+shapeMode
+
+public void shapeMode(int mode)
+
+
Set the orientation for the shape() command (like imageMode() or rectMode()).
+
Sets the alignment of the text to one of LEFT, CENTER, or RIGHT.
+ This will also reset the vertical text alignment to BASELINE.
+
+
+
+
+
+
+
+
+
+
+
+textAlign
+
+public void textAlign(int alignX,
+ int alignY)
+
+
Sets the horizontal and vertical alignment of the text. The horizontal
+ alignment can be one of LEFT, CENTER, or RIGHT. The vertical alignment
+ can be TOP, BOTTOM, CENTER, or the BASELINE (the default).
+
+
+
+
+
+
+
+
+
+
+
+textAscent
+
+public float textAscent()
+
+
Returns the ascent of the current font at the current size.
+ This is a method, rather than a variable inside the PGraphics object
+ because it requires calculation.
+
+
+
+
+
+
+
+
+
+
+
+textDescent
+
+public float textDescent()
+
+
Returns the descent of the current font at the current size.
+ This is a method, rather than a variable inside the PGraphics object
+ because it requires calculation.
+
Sets the current font. The font's size will be the "natural"
+ size of this font (the size that was set when using "Create Font").
+ The leading will also be reset.
+
Useful function to set the font and size at the same time.
+
+
+
+
+
+
+
+
+
+
+
+textLeading
+
+public void textLeading(float leading)
+
+
Set the text leading to a specific value. If using a custom
+ value for the text leading, you'll have to call textLeading()
+ again after any calls to textSize().
+
+
+
+
+
+
+
+
+
+
+
+textMode
+
+public void textMode(int mode)
+
+
Sets the text rendering/placement to be either SCREEN (direct
+ to the screen, exact coordinates, only use the font's original size)
+ or MODEL (the default, where text is manipulated by translate() and
+ can have a textSize). The text size cannot be set when using
+ textMode(SCREEN), because it uses the pixels directly from the font.
+
+
+
+
+
+
+
+
+
+
+
+textSize
+
+public void textSize(float size)
+
+
Sets the text size, also resets the value for the leading.
+
+
+
+
+
+
+
+
+
+
+
+textWidth
+
+public float textWidth(char c)
+
+
+
+
+
+
+
+
+
+
+
+textWidth
+
+public float textWidth(java.lang.String str)
+
+
Return the width of a line of text. If the text has multiple
+ lines, this returns the length of the longest line.
+
+
+
+
+
+
+
+
+
+
+
+text
+
+public void text(char c)
+
+
Write text where we just left off.
+
+
+
+
+
+
+
+
+
+
+
+text
+
+public void text(char c,
+ float x,
+ float y)
+
+
Draw a single character on screen.
+ Extremely slow when used with textMode(SCREEN) and Java 2D,
+ because loadPixels has to be called first and updatePixels last.
+
Draw a chunk of text.
+ Newlines that are \n (Unix newline or linefeed char, ascii 10)
+ are honored, but \r (carriage return, Windows and Mac OS) are
+ ignored.
+
+
+
+
+
+
+
+
+
+
+
+text
+
+public void text(char[] chars,
+ int start,
+ int stop,
+ float x,
+ float y)
+
+
Method to draw text from an array of chars. This method will usually be
+ more efficient than drawing from a String object, because the String will
+ not be converted to a char array before drawing.
+
Draw text in a box that is constrained to a particular size.
+ The current rectMode() determines what the coordinates mean
+ (whether x1/y1/x2/y2 or x/y/w/h).
+
+ Note that the x,y coords of the start of the box
+ will align with the *ascent* of the text, not the baseline,
+ as is the case for the other text() functions.
+
+ Newlines that are \n (Unix newline or linefeed char, ascii 10)
+ are honored, and \r (carriage return, Windows and Mac OS) are
+ ignored.
+
This does a basic number formatting, to avoid the
+ generally ugly appearance of printing floats.
+ Users who want more control should use their own nf() cmmand,
+ or if they want the long, ugly version of float,
+ use String.valueOf() to convert the float to a String first.
+
Two dimensional rotation.
+
+ Same as rotateZ (this is identical to a 3D rotation along the z-axis)
+ but included for clarity. It'd be weird for people drawing 2D graphics
+ to be using rotateZ. And they might kick our a-- for the confusion.
+
+ Additional background.
+
+
+
+
+
+
+
+
+
+
+
+rotateX
+
+public void rotateX(float angle)
+
+
Rotate around the X axis.
+
+
+
+
+
+
+
+
+
+
+
+rotateY
+
+public void rotateY(float angle)
+
+
Rotate around the Y axis.
+
+
+
+
+
+
+
+
+
+
+
+rotateZ
+
+public void rotateZ(float angle)
+
+
Rotate around the Z axis.
+
+ The functions rotate() and rotateZ() are identical, it's just that it make
+ sense to have rotate() and then rotateX() and rotateY() when using 3D;
+ nor does it make sense to use a function called rotateZ() if you're only
+ doing things in 2D. so we just decided to have them both be the same.
+
Rotate about a vector in space. Same as the glRotatef() function.
+
+
+
+
+
+
+
+
+
+
+
+scale
+
+public void scale(float s)
+
+
Scale in all dimensions.
+
+
+
+
+
+
+
+
+
+
+
+scale
+
+public void scale(float sx,
+ float sy)
+
+
Scale in X and Y. Equivalent to scale(sx, sy, 1).
+
+ Not recommended for use in 3D, because the z-dimension is just
+ scaled by 1, since there's no way to know what else to scale it by.
+
+
+
+
+
+
+
+
+
+
+
+scale
+
+public void scale(float x,
+ float y,
+ float z)
+
+
Scale in X, Y, and Z.
+
+
+
+
+
+
+
+
+
+
+
+resetMatrix
+
+public void resetMatrix()
+
+
Set the current transformation matrix to identity.
+
Given an x and y coordinate, returns the x position of where
+ that point would be placed on screen, once affected by translate(),
+ scale(), or any other transformations.
+
+
+
+
+
+
+
+
+
+
+
+screenY
+
+public float screenY(float x,
+ float y)
+
+
Given an x and y coordinate, returns the y position of where
+ that point would be placed on screen, once affected by translate(),
+ scale(), or any other transformations.
+
+
+
+
+
+
+
+
+
+
+
+screenX
+
+public float screenX(float x,
+ float y,
+ float z)
+
+
Maps a three dimensional point to its placement on-screen.
+
+ Given an (x, y, z) coordinate, returns the x position of where
+ that point would be placed on screen, once affected by translate(),
+ scale(), or any other transformations.
+
+
+
+
+
+
+
+
+
+
+
+screenY
+
+public float screenY(float x,
+ float y,
+ float z)
+
+
Maps a three dimensional point to its placement on-screen.
+
+ Given an (x, y, z) coordinate, returns the y position of where
+ that point would be placed on screen, once affected by translate(),
+ scale(), or any other transformations.
+
+
+
+
+
+
+
+
+
+
+
+screenZ
+
+public float screenZ(float x,
+ float y,
+ float z)
+
+
Maps a three dimensional point to its placement on-screen.
+
+ Given an (x, y, z) coordinate, returns its z value.
+ This value can be used to determine if an (x, y, z) coordinate
+ is in front or in back of another (x, y, z) coordinate.
+ The units are based on how the zbuffer is set up, and don't
+ relate to anything "real". They're only useful for in
+ comparison to another value obtained from screenZ(),
+ or directly out of the zbuffer[].
+
+
+
+
+
+
+
+
+
+
+
+modelX
+
+public float modelX(float x,
+ float y,
+ float z)
+
+
Returns the model space x value for an x, y, z coordinate.
+
+ This will give you a coordinate after it has been transformed
+ by translate(), rotate(), and camera(), but not yet transformed
+ by the projection matrix. For instance, his can be useful for
+ figuring out how points in 3D space relate to the edge
+ coordinates of a shape.
+
+
+
+
+
+
+
+
+
+
+
+modelY
+
+public float modelY(float x,
+ float y,
+ float z)
+
+
Returns the model space y value for an x, y, z coordinate.
+
+
+
+
+
+
+
+
+
+
+
+modelZ
+
+public float modelZ(float x,
+ float y,
+ float z)
+
+
Returns the model space z value for an x, y, z coordinate.
+
+public void lightSpecular(float x,
+ float y,
+ float z)
+
+
+
+
+
+
+
+
+
+
+
+background
+
+public void background(int rgb)
+
+
Set the background to a gray or ARGB color.
+
+ For the main drawing surface, the alpha value will be ignored. However,
+ alpha can be used on PGraphics objects from createGraphics(). This is
+ the only way to set all the pixels partially transparent, for instance.
+
+ Note that background() should be called before any transformations occur,
+ because some implementations may require the current transformation matrix
+ to be identity before drawing.
+
+
+
+
+
+
+
+
+
+
+
+background
+
+public void background(int rgb,
+ float alpha)
+
+
See notes about alpha in background(x, y, z, a).
+
+
+
+
+
+
+
+
+
+
+
+background
+
+public void background(float gray)
+
+
Set the background to a grayscale value, based on the
+ current colorMode.
+
See notes about alpha in background(x, y, z, a).
+
+
+
+
+
+
+
+
+
+
+
+background
+
+public void background(float x,
+ float y,
+ float z)
+
+
Set the background to an r, g, b or h, s, b value,
+ based on the current colorMode.
+
+
+
+
+
+
+
+
+
+
+
+background
+
+public void background(float x,
+ float y,
+ float z,
+ float a)
+
+
Clear the background with a color that includes an alpha value. This can
+ only be used with objects created by createGraphics(), because the main
+ drawing surface cannot be set transparent.
+
+ It might be tempting to use this function to partially clear the screen
+ on each frame, however that's not how this function works. When calling
+ background(), the pixels will be replaced with pixels that have that level
+ of transparency. To do a semi-transparent overlay, use fill() with alpha
+ and draw a rectangle.
+
Takes an RGB or ARGB image and sets it as the background.
+ The width and height of the image must be the same size as the sketch.
+ Use image.resize(width, height) to make short work of such a task.
+
+ Note that even if the image is set as RGB, the high 8 bits of each pixel
+ should be set opaque (0xFF000000), because the image data will be copied
+ directly to the screen, and non-opaque background images may have strange
+ behavior. Using image.filter(OPAQUE) will handle this easily.
+
+ When using 3D, this will also clear the zbuffer (if it exists).
+
+
+
+
+
+
+
+
+
+
+
+colorMode
+
+public void colorMode(int mode)
+
+
Callback to handle clearing the background when begin/endRaw is in use.
+ Handled as separate function for OpenGL (or other) subclasses that
+ override backgroundImpl() but still needs this to work properly.
+
Show an renderer-related exception that halts the program. Currently just
+ wraps the message as a RuntimeException and throws it, but might do
+ something more specific might be used in the future.
+
+
+
+
+
+
+
+
+
+
+
+displayable
+
+public boolean displayable()
+
+
Return true if this renderer should be drawn to the screen. Defaults to
+ returning true, since nearly all renderers are on-screen beasts. But can
+ be overridden for subclasses like PDF so that a window doesn't open up.
+
+ A better name? showFrame, displayable, isVisible, visible, shouldDisplay,
+ what to call this?
+
+
+
+
+
+
+
+
+
+
+
+is2D
+
+public boolean is2D()
+
+
Return true if this renderer supports 2D drawing. Defaults to true.
+
+
+
+
+
+
+
+
+
+
+
+is3D
+
+public boolean is3D()
+
+
Return true if this renderer supports 2D drawing. Defaults to true.
+
+Subclass of PGraphics that handles fast 2D rendering using a
+ MemoryImageSource. The renderer found in this class is not as accurate as
+ PGraphicsJava2D, but offers certain speed tradeoffs, particular when
+ messing with the pixels array, or displaying image or video data.
+
+
+
+
+
+
+
+
+
+
+
+
+Field Summary
+
+
+
+
+
+
Fields inherited from class processing.core.PGraphics
scale(float sx,
+ float sy)
+
+
+ Scale in X and Y.
+
+
+
+ void
+
scale(float x,
+ float y,
+ float z)
+
+
+ Scale in X, Y, and Z.
+
+
+
+ float
+
screenX(float x,
+ float y)
+
+
+ Given an x and y coordinate, returns the x position of where
+ that point would be placed on screen, once affected by translate(),
+ scale(), or any other transformations.
+
+
+
+ float
+
screenY(float x,
+ float y)
+
+
+ Given an x and y coordinate, returns the y position of where
+ that point would be placed on screen, once affected by translate(),
+ scale(), or any other transformations.
+
+
+
+ void
+
sphere(float r)
+
+
+ Draw a sphere with radius r centered at coordinate 0, 0, 0.
This will finalize rendering so that it can be shown on-screen.
+
+ When creating your own PGraphics, you should call this when
+ you're finished drawing.
+
+ Differences between beginShape() and line() and point() methods.
+
+ beginShape() is intended to be more flexible at the expense of being
+ a little more complicated to use. it handles more complicated shapes
+ that can consist of many connected lines (so you get joins) or lines
+ mixed with curves.
+
+ The line() and point() command are for the far more common cases
+ (particularly for our audience) that simply need to draw a line
+ or a point on the screen.
+
+ From the code side of things, line() may or may not call beginShape()
+ to do the drawing. In the beta code, they do, but in the alpha code,
+ they did not. they might be implemented one way or the other depending
+ on tradeoffs of runtime efficiency vs. implementation efficiency &mdash
+ meaning the speed that things run at vs. the speed it takes me to write
+ the code and maintain it. for beta, the latter is most important so
+ that's how things are implemented.
+
Set the detail level for approximating a sphere. The ures and vres params
+ control the horizontal and vertical resolution.
+
+ Code for sphereDetail() submitted by toxi [031031].
+ Code for enhanced u/v version from davbol [080801].
+
Draw a sphere with radius r centered at coordinate 0, 0, 0.
+
+ Implementation notes:
+
+ cache all the points of the sphere in a static array
+ top and bottom are just a bunch of triangles that land
+ in the center point
+
+ sphere is a series of concentric circles who radii vary
+ along the shape, based on, er.. cos or something
+
+ [toxi 031031] new sphere code. removed all multiplies with
+ radius, as scale() will take care of that anyway
+
+ [toxi 031223] updated sphere code (removed modulos)
+ and introduced sphereAt(x,y,z,r)
+ to avoid additional translate()'s on the user/sketch side
+
+ [davbol 080801] now using separate sphereDetailU/V
+
Two dimensional rotation.
+
+ Same as rotateZ (this is identical to a 3D rotation along the z-axis)
+ but included for clarity. It'd be weird for people drawing 2D graphics
+ to be using rotateZ. And they might kick our a-- for the confusion.
+
+ Additional background.
+
Rotate around the Z axis.
+
+ The functions rotate() and rotateZ() are identical, it's just that it make
+ sense to have rotate() and then rotateX() and rotateY() when using 3D;
+ nor does it make sense to use a function called rotateZ() if you're only
+ doing things in 2D. so we just decided to have them both be the same.
+
Scale in X and Y. Equivalent to scale(sx, sy, 1).
+
+ Not recommended for use in 3D, because the z-dimension is just
+ scaled by 1, since there's no way to know what else to scale it by.
+
Given an x and y coordinate, returns the x position of where
+ that point would be placed on screen, once affected by translate(),
+ scale(), or any other transformations.
+
Given an x and y coordinate, returns the y position of where
+ that point would be placed on screen, once affected by translate(),
+ scale(), or any other transformations.
+
+Subclass of PGraphics that handles 3D rendering.
+ It can render 3D inside a browser window and requires no plug-ins.
+
+ The renderer is mostly set up based on the structure of the OpenGL API,
+ if you have questions about specifics that aren't covered here,
+ look for reference on the OpenGL implementation of a similar feature.
+
+ Lighting and camera implementation by Simon Greenwold.
+
flush()
+
+
+ Emit any sorted geometry that's been collected on this frame.
+
+
+
+ void
+
frustum(float left,
+ float right,
+ float bottom,
+ float top,
+ float znear,
+ float zfar)
+
+
+ Same as glFrustum(), except that it wipes out (rather than
+ multiplies against) the current perspective matrix.
ortho()
+
+
+ Calls ortho() with the proper parameters for Processing's
+ standard orthographic projection.
+
+
+
+ void
+
ortho(float left,
+ float right,
+ float bottom,
+ float top,
+ float near,
+ float far)
+
+
+ Similar to gluOrtho(), but wipes out the current projection matrix.
+
+
+
+ void
+
perspective()
+
+
+ Calls perspective() with Processing's standard coordinate projection.
+
+
+
+ void
+
perspective(float fov,
+ float aspect,
+ float zNear,
+ float zFar)
+
+
+ Similar to gluPerspective().
popMatrix()
+
+
+ Replace the current transformation matrix with the top of the stack.
+
+
+
+ void
+
printCamera()
+
+
+ Print the current camera matrix.
+
+
+
+ void
+
printMatrix()
+
+
+ Print the current model (or "transformation") matrix.
+
+
+
+ void
+
printProjection()
+
+
+ Print the current projection matrix.
+
+
+
+ void
+
pushMatrix()
+
+
+ Push a copy of the current transformation matrix onto the stack.
+
+
+
+ void
+
resetMatrix()
+
+
+ Set the current transformation matrix to identity.
+
+
+
+ void
+
rotate(float angle)
+
+
+ Two dimensional rotation.
+
+
+
+ void
+
rotate(float angle,
+ float v0,
+ float v1,
+ float v2)
+
+
+ Rotate around an arbitrary vector, similar to glRotate(),
+ except that it takes radians (instead of degrees).
+
+
+
+ void
+
rotateX(float angle)
+
+
+ Rotate around the X axis.
+
+
+
+ void
+
rotateY(float angle)
+
+
+ Rotate around the Y axis.
+
+
+
+ void
+
rotateZ(float angle)
+
+
+ Rotate around the Z axis.
scale(float sx,
+ float sy)
+
+
+ Same as scale(sx, sy, 1).
+
+
+
+ void
+
scale(float x,
+ float y,
+ float z)
+
+
+ Scale in three dimensions.
+
+
+
+ float
+
screenX(float x,
+ float y)
+
+
+ Given an x and y coordinate, returns the x position of where
+ that point would be placed on screen, once affected by translate(),
+ scale(), or any other transformations.
+
+
+
+ float
+
screenX(float x,
+ float y,
+ float z)
+
+
+ Maps a three dimensional point to its placement on-screen.
+
+
+
+ float
+
screenY(float x,
+ float y)
+
+
+ Given an x and y coordinate, returns the y position of where
+ that point would be placed on screen, once affected by translate(),
+ scale(), or any other transformations.
+
+
+
+ float
+
screenY(float x,
+ float y,
+ float z)
+
+
+ Maps a three dimensional point to its placement on-screen.
+
+
+
+ float
+
screenZ(float x,
+ float y,
+ float z)
+
+
+ Maps a three dimensional point to its placement on-screen.
+
+
+
+ void
+
setMatrix(PMatrix2D source)
+
+
+ Set the current transformation to the contents of the specified source.
+
+
+
+ void
+
setMatrix(PMatrix3D source)
+
+
+ Set the current transformation to the contents of the specified source.
+
+
+
+ void
+
setSize(int iwidth,
+ int iheight)
+
+
+ Called in response to a resize event, handles setting the
+ new width and height internally, as well as re-allocating
+ the pixel buffer for the new size.
+
+
+
+ void
+
smooth()
+
+
+ If true in PImage, use bilinear interpolation for copy()
+ operations.
+
+
+
+ void
+
sphere(float r)
+
+
+ Draw a sphere with radius r centered at coordinate 0, 0, 0.
Called in response to a resize event, handles setting the
+ new width and height internally, as well as re-allocating
+ the pixel buffer for the new size.
+
+ Note that this will nuke any cameraMode() settings.
+
See notes in PGraphics.
+ If z-sorting has been turned on, then the triangles will
+ all be quicksorted here (to make alpha work more properly)
+ and then blit to the screen.
+
+ For the most part, hints are temporary api quirks,
+ for which a proper api hasn't been properly worked out.
+ for instance SMOOTH_IMAGES existed because smooth()
+ wasn't yet implemented, but it will soon go away.
+
+ They also exist for obscure features in the graphics
+ engine, like enabling/disabling single pixel lines
+ that ignore the zbuffer, the way they do in alphabot.
+
+ Current hint options:
+
+
DISABLE_DEPTH_TEST -
+ turns off the z-buffer in the P3D or OPENGL renderers.
+
+ Differences between beginShape() and line() and point() methods.
+
+ beginShape() is intended to be more flexible at the expense of being
+ a little more complicated to use. it handles more complicated shapes
+ that can consist of many connected lines (so you get joins) or lines
+ mixed with curves.
+
+ The line() and point() command are for the far more common cases
+ (particularly for our audience) that simply need to draw a line
+ or a point on the screen.
+
+ From the code side of things, line() may or may not call beginShape()
+ to do the drawing. In the beta code, they do, but in the alpha code,
+ they did not. they might be implemented one way or the other depending
+ on tradeoffs of runtime efficiency vs. implementation efficiency &mdash
+ meaning the speed that things run at vs. the speed it takes me to write
+ the code and maintain it. for beta, the latter is most important so
+ that's how things are implemented.
+
Draw a sphere with radius r centered at coordinate 0, 0, 0.
+
+ Implementation notes:
+
+ cache all the points of the sphere in a static array
+ top and bottom are just a bunch of triangles that land
+ in the center point
+
+ sphere is a series of concentric circles who radii vary
+ along the shape, based on, er.. cos or something
+
+ [toxi 031031] new sphere code. removed all multiplies with
+ radius, as scale() will take care of that anyway
+
+ [toxi 031223] updated sphere code (removed modulos)
+ and introduced sphereAt(x,y,z,r)
+ to avoid additional translate()'s on the user/sketch side
+
+ [davbol 080801] now using separate sphereDetailU/V
+
Two dimensional rotation. Same as rotateZ (this is identical
+ to a 3D rotation along the z-axis) but included for clarity --
+ it'd be weird for people drawing 2D graphics to be using rotateZ.
+ And they might kick our a-- for the confusion.
+
Rotate around the Z axis.
+
+ The functions rotate() and rotateZ() are identical, it's just that it make
+ sense to have rotate() and then rotateX() and rotateY() when using 3D;
+ nor does it make sense to use a function called rotateZ() if you're only
+ doing things in 2D. so we just decided to have them both be the same.
+
Apply a 4x4 transformation matrix. Same as glMultMatrix().
+ This call will be slow because it will try to calculate the
+ inverse of the transform. So avoid it whenever possible.
+
Set matrix mode to the camera matrix (instead of the current
+ transformation matrix). This means applyMatrix, resetMatrix, etc.
+ will affect the camera.
+
+ Note that the camera matrix is *not* the perspective matrix,
+ it is in front of the modelview matrix (hence the name "model"
+ and "view" for that matrix).
+
+ beginCamera() specifies that all coordinate transforms until endCamera()
+ should be pre-applied in inverse to the camera transform matrix.
+ Note that this is only challenging when a user specifies an arbitrary
+ matrix with applyMatrix(). Then that matrix will need to be inverted,
+ which may not be possible. But take heart, if a user is applying a
+ non-invertible matrix to the camera transform, then he is clearly
+ up to no good, and we can wash our hands of those bad intentions.
+
+ begin/endCamera clauses do not automatically reset the camera transform
+ matrix. That's because we set up a nice default camera transform int
+ setup(), and we expect it to hold through draw(). So we don't reset
+ the camera transform matrix at the top of draw(). That means that an
+ innocuous-looking clause like
+
+ at the top of draw(), will result in a runaway camera that shoots
+ infinitely out of the screen over time. In order to prevent this,
+ it is necessary to call some function that does a hard reset of the
+ camera transform matrix inside of begin/endCamera. Two options are
+
+ camera(); // sets up the nice default camera transform
+ resetMatrix(); // sets up the identity camera transform
+
+ So to rotate a camera a constant amount, you might try
+
Record the current settings into the camera matrix, and set
+ the matrix mode back to the current transformation matrix.
+
+ Note that this will destroy any settings to scale(), translate(),
+ or whatever, because the final camera matrix will be copied
+ (not multiplied) into the modelview.
+
+ Camera behavior can be split into two separate components, camera
+ transformation, and projection. The transformation corresponds to the
+ physical location, orientation, and scale of the camera. In a physical
+ camera metaphor, this is what can manipulated by handling the camera
+ body (with the exception of scale, which doesn't really have a physcial
+ analog). The projection corresponds to what can be changed by
+ manipulating the lens.
+
+ We maintain separate matrices to represent the camera transform and
+ projection. An important distinction between the two is that the camera
+ transform should be invertible, where the projection matrix should not,
+ since it serves to map three dimensions to two. It is possible to bake
+ the two matrices into a single one just by multiplying them together,
+ but it isn't a good idea, since lighting, z-ordering, and z-buffering
+ all demand a true camera z coordinate after modelview and camera
+ transforms have been applied but before projection. If the camera
+ transform and projection are combined there is no way to recover a
+ good camera-space z-coordinate from a model coordinate.
+
+ Fortunately, there are no functions that manipulate both camera
+ transformation and projection.
+
+ camera() sets the camera position, orientation, and center of the scene.
+ It replaces the camera transform with a new one. This is different from
+ gluLookAt(), but I think the only reason that GLU's lookat doesn't fully
+ replace the camera matrix with the new one, but instead multiplies it,
+ is that GL doesn't enforce the separation of camera transform and
+ projection, so it wouldn't be safe (you'd probably stomp your projection).
+
+ The transformation functions are the same ones used to manipulate the
+ modelview matrix (scale, translate, rotate, etc.). But they are bracketed
+ with beginCamera(), endCamera() to indicate that they should apply
+ (in inverse), to the camera transformation matrix.
+
+ This differs considerably from camera transformation in OpenGL.
+ OpenGL only lets you say, apply everything from here out to the
+ projection or modelview matrix. This makes it very hard to treat camera
+ manipulation as if it were a physical camera. Imagine that you want to
+ move your camera 100 units forward. In OpenGL, you need to apply the
+ inverse of that transformation or else you'll move your scene 100 units
+ forward--whether or not you've specified modelview or projection matrix.
+ Remember they're just multiplied by model coods one after another.
+ So in order to treat a camera like a physical camera, it is necessary
+ to pre-apply inverse transforms to a matrix that will be applied to model
+ coordinates. OpenGL provides nothing of this sort, but Processing does!
+ This is the camera transform matrix.
+
+ do not need to be called from with beginCamera();/endCamera();
+ That's because they always apply to the camera transformation,
+ and they always totally replace it. That means that any coordinate
+ transforms done before camera(); in draw() will be wiped out.
+ It also means that camera() always operates in untransformed world
+ coordinates. Therefore it is always redundant to call resetMatrix();
+ before camera(); This isn't technically true of gluLookat, but it's
+ pretty much how it's used.
+
+ Now, beginCamera(); and endCamera(); are useful if you want to move
+ the camera around using transforms like translate(), etc. They will
+ wipe out any coordinate system transforms that occur before them in
+ draw(), but they will not automatically wipe out the camera transform.
+ This means that they should be at the top of draw(). It also means
+ that the following:
+
+ will result in a camera that spins without stopping. If you want to
+ just rotate a small constant amount, try this:
+
+ beginCamera();
+ camera(); // sets up the default view
+ rotateY(PI/8);
+ endCamera();
+
+ That will rotate a little off of the default view. Note that this
+ is entirely equivalent to
+
+ camera(); // sets up the default view
+ beginCamera();
+ rotateY(PI/8);
+ endCamera();
+
+ because camera() doesn't care whether or not it's inside a
+ begin/end clause. Basically it's safe to use camera() or
+ camera(ex, ey, ez, cx, cy, cz, ux, uy, uz) as naked calls because
+ they do all the matrix resetting automatically.
+
Calls perspective() with Processing's standard coordinate projection.
+
+ Projection functions:
+
+
frustrum()
+
ortho()
+
perspective()
+
+ Each of these three functions completely replaces the projection
+ matrix with a new one. They can be called inside setup(), and their
+ effects will be felt inside draw(). At the top of draw(), the projection
+ matrix is not reset. Therefore the last projection function to be
+ called always dominates. On resize, the default projection is always
+ established, which has perspective.
+
+ This behavior is pretty much familiar from OpenGL, except where
+ functions replace matrices, rather than multiplying against the
+ previous.
+
Given an x and y coordinate, returns the x position of where
+ that point would be placed on screen, once affected by translate(),
+ scale(), or any other transformations.
+
Given an x and y coordinate, returns the y position of where
+ that point would be placed on screen, once affected by translate(),
+ scale(), or any other transformations.
+
Maps a three dimensional point to its placement on-screen.
+
+ Given an (x, y, z) coordinate, returns the x position of where
+ that point would be placed on screen, once affected by translate(),
+ scale(), or any other transformations.
+
Maps a three dimensional point to its placement on-screen.
+
+ Given an (x, y, z) coordinate, returns the y position of where
+ that point would be placed on screen, once affected by translate(),
+ scale(), or any other transformations.
+
Maps a three dimensional point to its placement on-screen.
+
+ Given an (x, y, z) coordinate, returns its z value.
+ This value can be used to determine if an (x, y, z) coordinate
+ is in front or in back of another (x, y, z) coordinate.
+ The units are based on how the zbuffer is set up, and don't
+ relate to anything "real". They're only useful for in
+ comparison to another value obtained from screenZ(),
+ or directly out of the zbuffer[].
+
Returns the model space x value for an x, y, z coordinate.
+
+ This will give you a coordinate after it has been transformed
+ by translate(), rotate(), and camera(), but not yet transformed
+ by the projection matrix. For instance, his can be useful for
+ figuring out how points in 3D space relate to the edge
+ coordinates of a shape.
+
+ The Lighting Skinny:
+
+ The way lighting works is complicated enough that it's worth
+ producing a document to describe it. Lighting calculations proceed
+ pretty much exactly as described in the OpenGL red book.
+
+ Light-affecting material properties:
+
+ AMBIENT COLOR
+ - multiplies by light's ambient component
+ - for believability this should match diffuse color
+
+ DIFFUSE COLOR
+ - multiplies by light's diffuse component
+
+ SPECULAR COLOR
+ - multiplies by light's specular component
+ - usually less colored than diffuse/ambient
+
+ SHININESS
+ - the concentration of specular effect
+ - this should be set pretty high (20-50) to see really
+ noticeable specularity
+
+ EMISSIVE COLOR
+ - constant additive color effect
+
+ Light types:
+
+ AMBIENT
+ - one color
+ - no specular color
+ - no direction
+ - may have falloff (constant, linear, and quadratic)
+ - may have position (which matters in non-constant falloff case)
+ - multiplies by a material's ambient reflection
+
+ DIRECTIONAL
+ - has diffuse color
+ - has specular color
+ - has direction
+ - no position
+ - no falloff
+ - multiplies by a material's diffuse and specular reflections
+
+ POINT
+ - has diffuse color
+ - has specular color
+ - has position
+ - no direction
+ - may have falloff (constant, linear, and quadratic)
+ - multiplies by a material's diffuse and specular reflections
+
+ SPOT
+ - has diffuse color
+ - has specular color
+ - has position
+ - has direction
+ - has cone angle (set to half the total cone angle)
+ - has concentration value
+ - may have falloff (constant, linear, and quadratic)
+ - multiplies by a material's diffuse and specular reflections
+
+ Normal modes:
+
+ All of the primitives (rect, box, sphere, etc.) have their normals
+ set nicely. During beginShape/endShape normals can be set by the user.
+
+ AUTO-NORMAL
+ - if no normal is set during the shape, we are in auto-normal mode
+ - auto-normal calculates one normal per triangle (face-normal mode)
+
+ SHAPE-NORMAL
+ - if one normal is set during the shape, it will be used for
+ all vertices
+
+ VERTEX-NORMAL
+ - if multiple normals are set, each normal applies to
+ subsequent vertices
+ - (except for the first one, which applies to previous
+ and subsequent vertices)
+
+ Efficiency consequences:
+
+ There is a major efficiency consequence of position-dependent
+ lighting calculations per vertex. (See below for determining
+ whether lighting is vertex position-dependent.) If there is no
+ position dependency then the only factors that affect the lighting
+ contribution per vertex are its colors and its normal.
+ There is a major efficiency win if
+
+ 1) lighting is not position dependent
+ 2) we are in AUTO-NORMAL or SHAPE-NORMAL mode
+
+ because then we can calculate one lighting contribution per shape
+ (SHAPE-NORMAL) or per triangle (AUTO-NORMAL) and simply multiply it
+ into the vertex colors. The converse is our worst-case performance when
+
+ 1) lighting is position dependent
+ 2) we are in AUTO-NORMAL mode
+
+ because then we must calculate lighting per-face * per-vertex.
+ Each vertex has a different lighting contribution per face in
+ which it appears. Yuck.
+
+ Determining vertex position dependency:
+
+ If any of the following factors are TRUE then lighting is
+ vertex position dependent:
+
+ 1) Any lights uses non-constant falloff
+ 2) There are any point or spot lights
+ 3) There is a light with specular color AND there is a
+ material with specular color
+
+ So worth noting is that default lighting (a no-falloff ambient
+ and a directional without specularity) is not position-dependent.
+ We should capitalize.
+
+ Simon Greenwold, April 2005
+
Add an ambient light based on the current color mode.
+ This version includes an (x, y, z) position for situations
+ where the falloff distance is used.
+
+Subclass for PGraphics that implements the graphics API using Java2D.
+
+
Pixel operations too slow? As of release 0085 (the first beta),
+ the default renderer uses Java2D. It's more accurate than the renderer
+ used in alpha releases of Processing (it handles stroke caps and joins,
+ and has better polygon tessellation), but it's super slow for handling
+ pixels. At least until we get a chance to get the old 2D renderer
+ (now called P2D) working in a similar fashion, you can use
+ size(w, h, P3D) instead of size(w, h) which will
+ be faster for general pixel flipping madness.
+
+
To get access to the Java 2D "Graphics2D" object for the default
+ renderer, use:
+
Graphics2D g2 = ((PGraphicsJava2D)g).g2;
+ This will let you do Java 2D stuff directly, but is not supported in
+ any way shape or form. Which just means "have fun, but don't complain
+ if it breaks."
breakShape()
+
+
+ This feature is in testing, do not use or rely upon its implementation
+
+
+
+ boolean
+
canDraw()
+
+
+ Some renderers have requirements re: when they are ready to draw.
+
+
+
+ void
+
copy(int sx,
+ int sy,
+ int sw,
+ int sh,
+ int dx,
+ int dy,
+ int dw,
+ int dh)
+
+
+ Copy things from one area of this image
+ to another area in the same image.
getImpl(int x,
+ int y,
+ int w,
+ int h)
+
+
+ Internal function to actually handle getting a block of pixels that
+ has already been properly cropped to a valid region.
scale(float sx,
+ float sy)
+
+
+ Scale in X and Y.
+
+
+
+ void
+
scale(float sx,
+ float sy,
+ float sz)
+
+
+ Scale in X, Y, and Z.
+
+
+
+ float
+
screenX(float x,
+ float y)
+
+
+ Given an x and y coordinate, returns the x position of where
+ that point would be placed on screen, once affected by translate(),
+ scale(), or any other transformations.
+
+
+
+ float
+
screenX(float x,
+ float y,
+ float z)
+
+
+ Maps a three dimensional point to its placement on-screen.
+
+
+
+ float
+
screenY(float x,
+ float y)
+
+
+ Given an x and y coordinate, returns the y position of where
+ that point would be placed on screen, once affected by translate(),
+ scale(), or any other transformations.
+
+
+
+ float
+
screenY(float x,
+ float y,
+ float z)
+
+
+ Maps a three dimensional point to its placement on-screen.
+
+
+
+ float
+
screenZ(float x,
+ float y,
+ float z)
+
+
+ Maps a three dimensional point to its placement on-screen.
+
+
+
+ void
+
set(int x,
+ int y,
+ int argb)
+
+
+ Set a single pixel to the specified color.
+
+
+
+ void
+
setMatrix(PMatrix2D source)
+
+
+ Set the current transformation to the contents of the specified source.
+
+
+
+ void
+
setMatrix(PMatrix3D source)
+
+
+ Set the current transformation to the contents of the specified source.
+
+
+
+ void
+
setSize(int iwidth,
+ int iheight)
+
+
+ Called in response to a resize event, handles setting the
+ new width and height internally, as well as re-allocating
+ the pixel buffer for the new size.
+
+
+
+ void
+
smooth()
+
+
+ If true in PImage, use bilinear interpolation for copy()
+ operations.
+
+
+
+ void
+
sphere(float r)
+
+
+ Draw a sphere with radius r centered at coordinate 0, 0, 0.
Called in response to a resize event, handles setting the
+ new width and height internally, as well as re-allocating
+ the pixel buffer for the new size.
+
+ Note that this will nuke any cameraMode() settings.
+
This will finalize rendering so that it can be shown on-screen.
+
+ When creating your own PGraphics, you should call this when
+ you're finished drawing.
+
+ Differences between beginShape() and line() and point() methods.
+
+ beginShape() is intended to be more flexible at the expense of being
+ a little more complicated to use. it handles more complicated shapes
+ that can consist of many connected lines (so you get joins) or lines
+ mixed with curves.
+
+ The line() and point() command are for the far more common cases
+ (particularly for our audience) that simply need to draw a line
+ or a point on the screen.
+
+ From the code side of things, line() may or may not call beginShape()
+ to do the drawing. In the beta code, they do, but in the alpha code,
+ they did not. they might be implemented one way or the other depending
+ on tradeoffs of runtime efficiency vs. implementation efficiency &mdash
+ meaning the speed that things run at vs. the speed it takes me to write
+ the code and maintain it. for beta, the latter is most important so
+ that's how things are implemented.
+
Draw a sphere with radius r centered at coordinate 0, 0, 0.
+
+ Implementation notes:
+
+ cache all the points of the sphere in a static array
+ top and bottom are just a bunch of triangles that land
+ in the center point
+
+ sphere is a series of concentric circles who radii vary
+ along the shape, based on, er.. cos or something
+
+ [toxi 031031] new sphere code. removed all multiplies with
+ radius, as scale() will take care of that anyway
+
+ [toxi 031223] updated sphere code (removed modulos)
+ and introduced sphereAt(x,y,z,r)
+ to avoid additional translate()'s on the user/sketch side
+
+ [davbol 080801] now using separate sphereDetailU/V
+
Returns the ascent of the current font at the current size.
+ This is a method, rather than a variable inside the PGraphics object
+ because it requires calculation.
+
Returns the descent of the current font at the current size.
+ This is a method, rather than a variable inside the PGraphics object
+ because it requires calculation.
+
Two dimensional rotation.
+
+ Same as rotateZ (this is identical to a 3D rotation along the z-axis)
+ but included for clarity. It'd be weird for people drawing 2D graphics
+ to be using rotateZ. And they might kick our a-- for the confusion.
+
+ Additional background.
+
Rotate around the Z axis.
+
+ The functions rotate() and rotateZ() are identical, it's just that it make
+ sense to have rotate() and then rotateX() and rotateY() when using 3D;
+ nor does it make sense to use a function called rotateZ() if you're only
+ doing things in 2D. so we just decided to have them both be the same.
+
Scale in X and Y. Equivalent to scale(sx, sy, 1).
+
+ Not recommended for use in 3D, because the z-dimension is just
+ scaled by 1, since there's no way to know what else to scale it by.
+
Given an x and y coordinate, returns the x position of where
+ that point would be placed on screen, once affected by translate(),
+ scale(), or any other transformations.
+
Given an x and y coordinate, returns the y position of where
+ that point would be placed on screen, once affected by translate(),
+ scale(), or any other transformations.
+
Maps a three dimensional point to its placement on-screen.
+
+ Given an (x, y, z) coordinate, returns the x position of where
+ that point would be placed on screen, once affected by translate(),
+ scale(), or any other transformations.
+
Maps a three dimensional point to its placement on-screen.
+
+ Given an (x, y, z) coordinate, returns the y position of where
+ that point would be placed on screen, once affected by translate(),
+ scale(), or any other transformations.
+
Maps a three dimensional point to its placement on-screen.
+
+ Given an (x, y, z) coordinate, returns its z value.
+ This value can be used to determine if an (x, y, z) coordinate
+ is in front or in back of another (x, y, z) coordinate.
+ The units are based on how the zbuffer is set up, and don't
+ relate to anything "real". They're only useful for in
+ comparison to another value obtained from screenZ(),
+ or directly out of the zbuffer[].
+
Actual implementation of clearing the background, now that the
+ internal variables for background color have been set. Called by the
+ backgroundFromCalc() method, which is what all the other background()
+ methods call once the work is done.
+
Call this when you want to mess with the pixels[] array.
+
+ For subclasses where the pixels[] buffer isn't set by default,
+ this should copy all data into the pixels[] array
+
Returns an ARGB "color" type (a packed 32 bit int with the color.
+ If the coordinate is outside the image, zero is returned
+ (black, but completely transparent).
+
+ If the image is in RGB format (i.e. on a PVideo object),
+ the value will get its high bits set, just to avoid cases where
+ they haven't been set already.
+
+ If the image is in ALPHA format, this returns a white with its
+ alpha value set.
+
+ This function is included primarily for beginners. It is quite
+ slow because it has to check to see if the x, y that was provided
+ is inside the bounds, and then has to check to see what image
+ type it is. If you want things to be more efficient, access the
+ pixels[] array directly.
+
Internal function to actually handle getting a block of pixels that
+ has already been properly cropped to a valid region. That is, x/y/w/h
+ are guaranteed to be inside the image space, so the implementation can
+ use the fastest possible pixel copying method.
+
Set alpha channel for an image. Black colors in the source
+ image will make the destination image completely transparent,
+ and white will make things fully opaque. Gray values will
+ be in-between steps.
+
+ Strictly speaking the "blue" value from the source image is
+ used as the alpha color. For a fully grayscale image, this
+ is correct, but for a color image it's not 100% accurate.
+ For a more accurate conversion, first use filter(GRAY)
+ which will make the image into a "correct" grayscake by
+ performing a proper luminance-based conversion.
+
PImage()
+
+
+ Create an empty image object, set its format to RGB.
+
+
+
PImage(java.awt.Image img)
+
+
+ Construct a new PImage from a java.awt.Image.
+
+
+
PImage(int width,
+ int height)
+
+
+ Create a new RGB (alpha ignored) image of a specific size.
+
+
+
PImage(int width,
+ int height,
+ int format)
+
+
+
+
+
+
+
+
+
+
+
+
+Method Summary
+
+
+
+ void
+
blend(int sx,
+ int sy,
+ int sw,
+ int sh,
+ int dx,
+ int dy,
+ int dw,
+ int dh,
+ int mode)
+
+
+ Blends one area of this image to another area.
+
+
+
+ void
+
blend(PImage src,
+ int sx,
+ int sy,
+ int sw,
+ int sh,
+ int dx,
+ int dy,
+ int dw,
+ int dh,
+ int mode)
+
+
+ Copies area of one image into another PImage object.
+
+
+
+static int
+
blendColor(int c1,
+ int c2,
+ int mode)
+
+
+ Blend two colors based on a particular mode.
+
+
+
+ java.lang.Object
+
clone()
+
+
+ Duplicate an image, returns new PImage object.
+
+
+
+ void
+
copy(int sx,
+ int sy,
+ int sw,
+ int sh,
+ int dx,
+ int dy,
+ int dw,
+ int dh)
+
+
+ Copy things from one area of this image
+ to another area in the same image.
+
+
+
+ void
+
copy(PImage src,
+ int sx,
+ int sy,
+ int sw,
+ int sh,
+ int dx,
+ int dy,
+ int dw,
+ int dh)
+
+
+ Copies area of one image into another PImage object.
+
+
+
+ void
+
filter(int kind)
+
+
+ Method to apply a variety of basic filters to this image.
+
+
+
+ void
+
filter(int kind,
+ float param)
+
+
+ Method to apply a variety of basic filters to this image.
get(int x,
+ int y,
+ int w,
+ int h)
+
+
+ Grab a subsection of a PImage, and copy it into a fresh PImage.
+
+
+
+ java.lang.Object
+
getCache(java.lang.Object parent)
+
+
+ Get cache storage data for the specified renderer.
+
+
+
+ java.awt.Image
+
getImage()
+
+
+ Returns a BufferedImage from this PImage.
+
+
+
+ void
+
init(int width,
+ int height,
+ int format)
+
+
+ Function to be used by subclasses of PImage to init later than
+ at the constructor, or re-init later when things changes.
loadPixels()
+
+
+ Call this when you want to mess with the pixels[] array.
+
+
+
+ void
+
mask(int[] alpha)
+
+
+ Set alpha channel for an image.
+
+
+
+ void
+
mask(PImage alpha)
+
+
+ Set alpha channel for an image using another image as the source.
+
+
+
+ void
+
removeCache(java.lang.Object parent)
+
+
+ Remove information associated with this renderer from the cache, if any.
+
+
+
+ void
+
resize(int wide,
+ int high)
+
+
+ Resize this image to a new width and height.
+
+
+
+ void
+
save(java.lang.String path)
+
+
+ Save this image to disk.
+
+
+
+ void
+
set(int x,
+ int y,
+ int c)
+
+
+ Set a single pixel to the specified color.
+
+
+
+ void
+
set(int x,
+ int y,
+ PImage src)
+
+
+ Efficient method of drawing an image's pixels directly to this surface.
+
+
+
+ void
+
setCache(java.lang.Object parent,
+ java.lang.Object storage)
+
+
+ Store data of some kind for a renderer that requires extra metadata of
+ some kind.
Format for this image, one of RGB, ARGB or ALPHA.
+ note that RGB images still require 0xff in the high byte
+ because of how they'll be manipulated by other functions
+
Path to parent object that will be used with save().
+ This prevents users from needing savePath() to use PImage.save().
+
+
+
+
+
+
+
+
+
+
+
+Constructor Detail
+
+
+
+
+PImage
+
+public PImage()
+
+
Create an empty image object, set its format to RGB.
+ The pixel array is not allocated.
+
+
+
+
+
+PImage
+
+public PImage(int width,
+ int height)
+
+
Create a new RGB (alpha ignored) image of a specific size.
+ All pixels are set to zero, meaning black, but since the
+ alpha is zero, it will be transparent.
+
+
+
+
+
+PImage
+
+public PImage(int width,
+ int height,
+ int format)
+
+
+
+
+
+PImage
+
+public PImage(java.awt.Image img)
+
+
Construct a new PImage from a java.awt.Image. This constructor assumes
+ that you've done the work of making sure a MediaTracker has been used
+ to fully download the data and that the img is valid.
+
+
+
+
+
+
+
+
+
+Method Detail
+
+
+
+
+init
+
+public void init(int width,
+ int height,
+ int format)
+
+
Function to be used by subclasses of PImage to init later than
+ at the constructor, or re-init later when things changes.
+ Used by Capture and Movie classes (and perhaps others),
+ because the width/height will not be known when super() is called.
+ (Leave this public so that other libraries can do the same.)
+
Store data of some kind for a renderer that requires extra metadata of
+ some kind. Usually this is a renderer-specific representation of the
+ image data, for instance a BufferedImage with tint() settings applied for
+ PGraphicsJava2D, or resized image data and OpenGL texture indices for
+ PGraphicsOpenGL.
+
Get cache storage data for the specified renderer. Because each renderer
+ will cache data in different formats, it's necessary to store cache data
+ keyed by the renderer object. Otherwise, attempting to draw the same
+ image to both a PGraphicsJava2D and a PGraphicsOpenGL will cause errors.
+
+
+
+
+
+
Parameters:
parent - The PGraphics object (or any object, really) associated
+
Returns:
data stored for the specified parent
+
+
+
+
+
+removeCache
+
+public void removeCache(java.lang.Object parent)
+
+
Remove information associated with this renderer from the cache, if any.
+
+
+
+
+
+
Parameters:
parent - The PGraphics object whose cache data should be removed
+
+
+
+
+
+isModified
+
+public boolean isModified()
+
+
+
+
+
+
+
+
+
+
+
+setModified
+
+public void setModified()
+
+
+
+
+
+
+
+
+
+
+
+setModified
+
+public void setModified(boolean m)
+
+
+
+
+
+
+
+
+
+
+
+loadPixels
+
+public void loadPixels()
+
+
Call this when you want to mess with the pixels[] array.
+
+ For subclasses where the pixels[] buffer isn't set by default,
+ this should copy all data into the pixels[] array
+
+
+
+
+
+
+
+
+
+
+
+updatePixels
+
+public void updatePixels()
+
+
Call this when finished messing with the pixels[] array.
+
+ Mark all pixels as needing update.
+
+
+
+
+
+
+
+
+
+
+
+updatePixels
+
+public void updatePixels(int x,
+ int y,
+ int w,
+ int h)
+
+
Mark the pixels in this region as needing an update.
+
+ This is not currently used by any of the renderers, however the api
+ is structured this way in the hope of being able to use this to
+ speed things up in the future.
+
Duplicate an image, returns new PImage object.
+ The pixels[] array for the new object will be unique
+ and recopied from the source image. This is implemented as an
+ override of Object.clone(). We recommend using get() instead,
+ because it prevents you from needing to catch the
+ CloneNotSupportedException, and from doing a cast from the result.
+
+
+
Overrides:
clone in class java.lang.Object
+
+
+
+
Throws:
+
java.lang.CloneNotSupportedException
+
+
+
+
+
+resize
+
+public void resize(int wide,
+ int high)
+
+
Resize this image to a new width and height.
+ Use 0 for wide or high to make that dimension scale proportionally.
+
+
+
+
+
+
+
+
+
+
+
+get
+
+public int get(int x,
+ int y)
+
+
Returns an ARGB "color" type (a packed 32 bit int with the color.
+ If the coordinate is outside the image, zero is returned
+ (black, but completely transparent).
+
+ If the image is in RGB format (i.e. on a PVideo object),
+ the value will get its high bits set, just to avoid cases where
+ they haven't been set already.
+
+ If the image is in ALPHA format, this returns a white with its
+ alpha value set.
+
+ This function is included primarily for beginners. It is quite
+ slow because it has to check to see if the x, y that was provided
+ is inside the bounds, and then has to check to see what image
+ type it is. If you want things to be more efficient, access the
+ pixels[] array directly.
+
+
+
+
+
+
+
+
+
+
+
+get
+
+public PImageget(int x,
+ int y,
+ int w,
+ int h)
+
+
Grab a subsection of a PImage, and copy it into a fresh PImage.
+ As of release 0149, no longer honors imageMode() for the coordinates.
+
Efficient method of drawing an image's pixels directly to this surface.
+ No variations are employed, meaning that any scale, tint, or imageMode
+ settings will be ignored.
+
+
+
+
+
+
+
+
+
+
+
+mask
+
+public void mask(int[] alpha)
+
+
Set alpha channel for an image. Black colors in the source
+ image will make the destination image completely transparent,
+ and white will make things fully opaque. Gray values will
+ be in-between steps.
+
+ Strictly speaking the "blue" value from the source image is
+ used as the alpha color. For a fully grayscale image, this
+ is correct, but for a color image it's not 100% accurate.
+ For a more accurate conversion, first use filter(GRAY)
+ which will make the image into a "correct" grayscake by
+ performing a proper luminance-based conversion.
+
Set alpha channel for an image using another image as the source.
+
+
+
+
+
+
+
+
+
+
+
+filter
+
+public void filter(int kind)
+
+
Method to apply a variety of basic filters to this image.
+
+
+
filter(BLUR) provides a basic blur.
+
filter(GRAY) converts the image to grayscale based on luminance.
+
filter(INVERT) will invert the color components in the image.
+
filter(OPAQUE) set all the high bits in the image to opaque
+
filter(THRESHOLD) converts the image to black and white.
+
filter(DILATE) grow white/light areas
+
filter(ERODE) shrink white/light areas
+
+ Luminance conversion code contributed by
+ toxi
+
+ Gaussian blur code contributed by
+ Mario Klingemann
+
+
+
+
+
+
+
+
+
+
+
+filter
+
+public void filter(int kind,
+ float param)
+
+
Method to apply a variety of basic filters to this image.
+ These filters all take a parameter.
+
+
+
filter(BLUR, int radius) performs a gaussian blur of the
+ specified radius.
+
filter(POSTERIZE, int levels) will posterize the image to
+ between 2 and 255 levels.
+
filter(THRESHOLD, float center) allows you to set the
+ center point for the threshold. It takes a value from 0 to 1.0.
+
+ Gaussian blur code contributed by
+ Mario Klingemann
+ and later updated by toxi for better speed.
+
+
+
+
+
+
+
+
+
+
+
+copy
+
+public void copy(int sx,
+ int sy,
+ int sw,
+ int sh,
+ int dx,
+ int dy,
+ int dw,
+ int dh)
+
+
Copy things from one area of this image
+ to another area in the same image.
+
+
+
+
+
+
+
+
+
+
+
+copy
+
+public void copy(PImage src,
+ int sx,
+ int sy,
+ int sw,
+ int sh,
+ int dx,
+ int dy,
+ int dw,
+ int dh)
+
+
Copies area of one image into another PImage object.
+
+
+
+
+
+
+
+
+
+
+
+blendColor
+
+public static int blendColor(int c1,
+ int c2,
+ int mode)
+
+
Blend two colors based on a particular mode.
+
+
REPLACE - destination colour equals colour of source pixel: C = A.
+ Sometimes called "Normal" or "Copy" in other software.
+
+
BLEND - linear interpolation of colours:
+ C = A*factor + B
+
+
ADD - additive blending with white clip:
+ C = min(A*factor + B, 255).
+ Clipped to 0..255, Photoshop calls this "Linear Burn",
+ and Director calls it "Add Pin".
+
+
SUBTRACT - substractive blend with black clip:
+ C = max(B - A*factor, 0).
+ Clipped to 0..255, Photoshop calls this "Linear Dodge",
+ and Director calls it "Subtract Pin".
+
+
DARKEST - only the darkest colour succeeds:
+ C = min(A*factor, B).
+ Illustrator calls this "Darken".
+
+
LIGHTEST - only the lightest colour succeeds:
+ C = max(A*factor, B).
+ Illustrator calls this "Lighten".
+
+
DIFFERENCE - subtract colors from underlying image.
+
+
EXCLUSION - similar to DIFFERENCE, but less extreme.
+
+
MULTIPLY - Multiply the colors, result will always be darker.
+
+
SCREEN - Opposite multiply, uses inverse values of the colors.
+
+
OVERLAY - A mix of MULTIPLY and SCREEN. Multiplies dark values,
+ and screens light values.
+
+
HARD_LIGHT - SCREEN when greater than 50% gray, MULTIPLY when lower.
+
+
SOFT_LIGHT - Mix of DARKEST and LIGHTEST.
+ Works like OVERLAY, but not as harsh.
+
+
DODGE - Lightens light tones and increases contrast, ignores darks.
+ Called "Color Dodge" in Illustrator and Photoshop.
+
+
BURN - Darker areas are applied, increasing contrast, ignores lights.
+ Called "Color Burn" in Illustrator and Photoshop.
+
+
A useful reference for blending modes and their algorithms can be
+ found in the SVG
+ specification.
+
It is important to note that Processing uses "fast" code, not
+ necessarily "correct" code. No biggie, most software does. A nitpicker
+ can find numerous "off by 1 division" problems in the blend code where
+ >>8 or >>7 is used when strictly speaking
+ /255.0 or /127.0 should have been used.
+
For instance, exclusion (not intended for real-time use) reads
+ r1 + r2 - ((2 * r1 * r2) / 255) because 255 == 1.0
+ not 256 == 1.0. In other words, (255*255)>>8 is not
+ the same as (255*255)/255. But for real-time use the shifts
+ are preferrable, and the difference is insignificant for applications
+ built with Processing.
+
+
+
+
+
+
+
+
+
+
+
+blend
+
+public void blend(int sx,
+ int sy,
+ int sw,
+ int sh,
+ int dx,
+ int dy,
+ int dw,
+ int dh,
+ int mode)
+ As of revision 0100, this function requires an absolute path,
+ in order to avoid confusion. To save inside the sketch folder,
+ use the function savePath() from PApplet, or use saveFrame() instead.
+ As of revision 0116, savePath() is not needed if this object has been
+ created (as recommended) via createImage() or createGraphics() or
+ one of its neighbors.
+
+ As of revision 0115, when using Java 1.4 and later, you can write
+ to several formats besides tga and tiff. If Java 1.4 is installed
+ and the extension used is supported (usually png, jpg, jpeg, bmp,
+ and tiff), then those methods will be used to write the image.
+ To get a list of the supported formats for writing, use:
+ println(javax.imageio.ImageIO.getReaderFormatNames())
+
+ To use the original built-in image writers, use .tga or .tif as the
+ extension, or don't include an extension. When no extension is used,
+ the extension .tif will be added to the file name.
+
+ The ImageIO API claims to support wbmp files, however they probably
+ require a black and white image. Basic testing produced a zero-length
+ file with no error.
+
Multiply a two element vector against this matrix.
+ If out is null or not length four, a new float array will be returned.
+ The values for vec and out can be the same (though that's less efficient).
+
+In-progress class to handle shape data, currently to be considered of
+ alpha or beta quality. Major structural work may be performed on this class
+ after the release of Processing 1.0. Such changes may include:
+
+
+
addition of proper accessors to read shape vertex and coloring data
+ (this is the second most important part of having a PShape class after all).
+
a means of creating PShape objects ala beginShape() and endShape().
+
load(), update(), and cache methods ala PImage, so that shapes can
+ have renderer-specific optimizations, such as vertex arrays in OpenGL.
+
splitting this class into multiple classes to handle different
+ varieties of shape data (primitives vs collections of vertices vs paths)
+
change of package declaration, for instance moving the code into
+ package processing.shape (if the code grows too much).
+
+
+
For the time being, this class and its shape() and loadShape() friends in
+ PApplet exist as placeholders for more exciting things to come. If you'd
+ like to work with this class, make a subclass (see how PShapeSVG works)
+ and you can play with its internal methods all you like.
+
+
Library developers are encouraged to create PShape objects when loading
+ shape data, so that they can eventually hook into the bounty that will be
+ the PShape interface, and the ease of loadShape() and shape().
findChild(java.lang.String target)
+
+
+ Same as getChild(name), except that it first walks all the way up the
+ hierarchy to the farthest parent, so that children can be found anywhere.
Overrides this shape's style information and uses PGraphics styles and
+ colors. Identical to ignoreStyles(true). Also disables styles for all
+ child shapes.
+
+
+
+
+
+
+
+
+
+
+
+enableStyle
+
+public void enableStyle()
+
+
Re-enables style information (fill and stroke) set in the shape.
+
+
+
+
+
+
+
+
+
+
+
+getWidth
+
+public float getWidth()
+
+
Get the width of the drawing area (not necessarily the shape boundary).
+
+
+
+
+
+
+
+
+
+
+
+getHeight
+
+public float getHeight()
+
+
Get the height of the drawing area (not necessarily the shape boundary).
+
+SVG stands for Scalable Vector Graphics, a portable graphics format. It is
+ a vector format so it allows for infinite resolution and relatively small
+ file sizes. Most modern media software can view SVG files, including Adobe
+ products, Firefox, etc. Illustrator and Inkscape can edit SVG files.
+
+ We have no intention of turning this into a full-featured SVG library.
+ The goal of this project is a basic shape importer that is small enough
+ to be included with applets, meaning that its download size should be
+ in the neighborhood of 25-30k. Starting with release 0149, this library
+ has been incorporated into the core via the loadShape() command, because
+ vector shape data is just as important as the image data from loadImage().
+
+ For more sophisticated import/export, consider the
+ Batik
+ library from the Apache Software Foundation. Future improvements to this
+ library may focus on this properly supporting a specific subset of SVG,
+ for instance the simpler SVG profiles known as
+ SVG Tiny or Basic,
+ although we still would not support the interactivity options.
+
+
+
+ A minimal example program using SVG:
+ (assuming a working moo.svg is in your data folder)
+
+
+
+ This code is based on the Candy library written by Michael Chang, which was
+ later revised and expanded for use as a Processing core library by Ben Fry.
+ Thanks to Ricard Marxer Pinon for help with better Inkscape support in 0154.
+
+
+
+ Late October 2008 revisions from ricardmp, incorporated by fry (0154)
+
Get a particular element based on its SVG ID. When editing SVG by hand,
+ this is the id="" tag on any SVG element. When editing from Illustrator,
+ these IDs can be edited by expanding the layers palette. The names used
+ in the layers palette, both for the layers or the shapes and groups
+ beneath them can be used here.
+
+ // This code grabs "Layer 3" and the shapes beneath it.
+ SVG layer3 = svg.getChild("Layer 3");
+
+Smoothed triangle renderer for P3D.
+
+ Based off of the PPolygon class in old versions of Processing.
+ Name and location of this class will change in a future release.
+
+
+
+
+
+
+
+
+
+
+
+
+Field Summary
+
+
+
+
+
+
Fields inherited from interface processing.core.PConstants
Pass camera-space coordinates for the triangle.
+ Needed to render if hint(ENABLE_ACCURATE_TEXTURES) enabled.
+ Generally this will not need to be called manually,
+ currently called from PGraphics3D.render_triangles()
+
Pass camera-space coordinates for the triangle.
+ Needed to render if hint(ENABLE_ACCURATE_TEXTURES) enabled.
+ Generally this will not need to be called manually,
+ currently called from PGraphics3D.render_triangles()
+
Set the power of two used for linear interpolation of texture coordinates.
+ A true texture coordinate is computed every 2^pwr pixels along a scanline.
+
+A class to describe a two or three dimensional vector.
+
+ The result of all functions are applied to the vector itself, with the
+ exception of cross(), which returns a new PVector (or writes to a specified
+ 'target' PVector). That is, add() will add the contents of one vector to
+ this one. Using add() with additional parameters allows you to put the
+ result into a new PVector. Functions that act on multiple vectors also
+ include static versions. Because creating new objects can be computationally
+ expensive, most functions include an optional 'target' PVector, so that a
+ new PVector object is not created with each operation.
+
+ Initially based on the Vector3D class by Dan Shiffman.
+
div(PVector v1,
+ PVector v2)
+
+
+ Multiply each element of one vector by the individual elements of another
+ vector, and return the result as a new PVector.
div(PVector v1,
+ PVector v2,
+ PVector target)
+
+
+ Divide each element of one vector by the individual elements of another
+ vector, and write the result into a target vector.
mult(PVector v1,
+ PVector v2)
+
+
+ Multiply each element of one vector by the individual elements of another
+ vector, and return the result as a new PVector.
mult(PVector v1,
+ PVector v2,
+ PVector target)
+
+
+ Multiply each element of one vector by the individual elements of another
+ vector, and write the result into a target vector.
+
+
+
+ void
+
normalize()
+
+
+ Normalize the vector to length 1 (make it a unit vector)
Calculate the angle between two vectors, using the dot product
+
+
+
Parameters:
v1 - a vector
v2 - another vector
+
Returns:
the angle between the vectors
+
+
+
+
+
+toString
+
+public java.lang.String toString()
+
+
+
Overrides:
toString in class java.lang.Object
+
+
+
+
+
+
+
+
+array
+
+public float[] array()
+
+
Return a representation of this vector as a float array. This is only for
+ temporary use. If used in any other fashion, the contents should be copied
+ by using the get() command to copy into your own array.
+
addAttribute(java.lang.String key,
+ java.lang.String nsPrefix,
+ java.lang.String nsURI,
+ java.lang.String value,
+ java.lang.String type)
+
+
+ This method is called when a new attribute of an XML element is
+ encountered.
+
+
+
+ void
+
addPCData(java.io.Reader reader,
+ java.lang.String systemID,
+ int lineNr)
+
+
+ This method is called when a PCDATA element is encountered.
+
+
+
+ void
+
elementAttributesProcessed(java.lang.String name,
+ java.lang.String nsPrefix,
+ java.lang.String nsURI)
+
+
+ This method is called when the attributes of an XML element have been
+ processed.
+
+
+
+ void
+
endElement(java.lang.String name,
+ java.lang.String nsPrefix,
+ java.lang.String nsURI)
+
+
+ This method is called when the end of an XML elemnt is encountered.
+
+
+
+ java.lang.Object
+
getResult()
+
+
+ Returns the result of the building process.
+
+
+
+ void
+
newProcessingInstruction(java.lang.String target,
+ java.io.Reader reader)
+
+
+ This method is called when a processing instruction is encountered.
+
+
+
+ void
+
startBuilding(java.lang.String systemID,
+ int lineNr)
+
+
+ This method is called before the parser starts processing its input.
+
+
+
+ void
+
startElement(java.lang.String name,
+ java.lang.String nsPrefix,
+ java.lang.String nsURI,
+ java.lang.String systemID,
+ int lineNr)
+
+
+ This method is called when a new XML element is encountered.
This method is called when a new attribute of an XML element is
+ encountered.
+
+
+
Parameters:
key - the key (name) of the attribute.
nsPrefix - the prefix used to identify the namespace. If no
+ namespace has been specified, this parameter is null.
nsURI - the URI associated with the namespace. If no
+ namespace has been specified, or no URI is
+ associated with nsPrefix, this parameter is null.
value - the value of the attribute.
type - the type of the attribute. If no type is known,
+ "CDATA" is returned.
+
Throws:
+
java.lang.Exception - If an exception occurred while processing the event.
+
+
+
+
+
+addPCData
+
+public void addPCData(java.io.Reader reader,
+ java.lang.String systemID,
+ int lineNr)
+
+
This method is called when a PCDATA element is encountered. A Java
+ reader is supplied from which you can read the data. The reader will
+ only read the data of the element. You don't need to check for
+ boundaries. If you don't read the full element, the rest of the data
+ is skipped. You also don't have to care about entities; they are
+ resolved by the parser.
+
+
+
Parameters:
reader - the Java reader from which you can retrieve the data.
systemID - the system ID of the XML data source.
lineNr - the line in the source where the element starts.
+
+
+
+
+
+getResult
+
+public java.lang.Object getResult()
+
+
Returns the result of the building process. This method is called just
+ before the parse method of StdXMLParser returns.
+
Starts a new stream from a Java reader. The new stream is used
+ temporary to read data from. If that stream is exhausted, control
+ returns to the parent stream.
+
+
+
Parameters:
reader - the non-null reader to read the new data from
Starts a new stream from a Java reader. The new stream is used
+ temporary to read data from. If that stream is exhausted, control
+ returns to the parent stream.
+
+
+
Parameters:
reader - the non-null reader to read the new data from
isInternalEntity - true if the reader is produced by resolving
+ an internal entity
+
+
+
+
+
+getStreamLevel
+
+public int getStreamLevel()
+
+
Returns the current "level" of the stream on the stack of streams.
+
+
+
+
+
+
+
+
+getLineNr
+
+public int getLineNr()
+
+
Returns the line number of the data in the current stream.
+
+XMLElement is an XML element. This is the base class used for the
+ Processing XML library, representing a single node of an XML tree.
+
+ This code is based on a modified version of NanoXML by Marc De Scheemaecker.
+
Begin parsing XML data passed in from a PApplet. This code
+ wraps exception handling, for more advanced exception handling,
+ use the constructor that takes a Reader or InputStream.
+
Return the #PCDATA content of the element. If the element has a
+ combination of #PCDATA content and child elements, the #PCDATA
+ sections can be retrieved as unnamed child objects. In this case,
+ this method returns null.
+
+
+
+
+
+
+
Returns:
the content.
+
+
+
+
+
+setContent
+
+public void setContent(java.lang.String content)
+
+
Sets the #PCDATA content. It is an error to call this method with a
+ non-null value if there are child objects.
+
+XMLValidator implementation based on NonValidator (which implemented
+ IXMLValidator in the original NanoXML).
+ This implementation processes the DTD and handles entity definitions.
+ It does not do any validation itself.
+
attributeAdded(java.lang.String key,
+ java.lang.String value,
+ java.lang.String systemId,
+ int lineNr)
+
+
+ Indicates that an attribute has been added to the current element.
+
+
+
+ void
+
elementAttributesProcessed(java.lang.String name,
+ java.util.Properties extraAttributes,
+ java.lang.String systemId,
+ int lineNr)
+
+
+ This method is called when the attributes of an XML element have been
+ processed.
+
+
+
+ void
+
elementEnded(java.lang.String name,
+ java.lang.String systemId,
+ int lineNr)
+
+
+ Indicates that the current element has ended.
+
+
+
+ void
+
elementStarted(java.lang.String name,
+ java.lang.String systemId,
+ int lineNr)
+
+
+ Indicates that an element has been started.
This method is called when the attributes of an XML element have been
+ processed.
+ If there are attributes with a default value which have not been
+ specified yet, they have to be put into extraAttributes.
+
+
+
Parameters:
name - the name of the element.
extraAttributes - where to put extra attributes.
systemId - the system ID of the XML data of the element.
lineNr - the line number in the XML data of the element.
The PGraphics renderer associated with this PApplet
+
+
+
+
+
+
+frame
+
+java.awt.Frame frame
+
+
The frame containing this applet (if any)
+
+
+
+
+
+
+screen
+
+java.awt.Dimension screen
+
+
The screen size when the applet was started.
+
+ Access this via screen.width and screen.height. To make an applet
+ run at full screen, use size(screen.width, screen.height).
+
+ If you have multiple displays, this will be the size of the main
+ display. Running full screen across multiple displays isn't
+ particularly supported, and requires more monkeying with the values.
+ This probably can't/won't be fixed until/unless I get a dual head
+ system.
+
+ Note that this won't update if you change the resolution
+ of your screen once the the applet is running.
+
+ This variable is not static, because future releases need to be better
+ at handling multiple displays.
+
A leech graphics object that is echoing all events.
+
+
+
+
+
+
+args
+
+java.lang.String[] args
+
+
Command line options passed in from main().
+
+ This does not include the arguments passed in to PApplet itself.
+
+
+
+
+
+
+sketchPath
+
+java.lang.String sketchPath
+
+
Path to sketch folder
+
+
+
+
+
+
+defaultSize
+
+boolean defaultSize
+
+
true if no size() command has been executed. This is used to wait until
+ a size has been set before placing in the window and showing it.
+
+
+
+
+
+
+resizeRequest
+
+boolean resizeRequest
+
+
+
+
+
+
+resizeWidth
+
+int resizeWidth
+
+
+
+
+
+
+resizeHeight
+
+int resizeHeight
+
+
+
+
+
+
+pixels
+
+int[] pixels
+
+
Pixel buffer from this applet's PGraphics.
+
+ When used with OpenGL or Java2D, this value will
+ be null until loadPixels() has been called.
+
+
+
+
+
+
+width
+
+int width
+
+
width of this applet's associated PGraphics
+
+
+
+
+
+
+height
+
+int height
+
+
height of this applet's associated PGraphics
+
+
+
+
+
+
+mouseX
+
+int mouseX
+
+
current x position of the mouse
+
+
+
+
+
+
+mouseY
+
+int mouseY
+
+
current y position of the mouse
+
+
+
+
+
+
+pmouseX
+
+int pmouseX
+
+
Previous x/y position of the mouse. This will be a different value
+ when inside a mouse handler (like the mouseMoved() method) versus
+ when inside draw(). Inside draw(), pmouseX is updated once each
+ frame, but inside mousePressed() and friends, it's updated each time
+ an event comes through. Be sure to use only one or the other type of
+ means for tracking pmouseX and pmouseY within your sketch, otherwise
+ you're gonna run into trouble.
+
+
+
+
+
+
+pmouseY
+
+int pmouseY
+
+
Previous x/y position of the mouse. This will be a different value
+ when inside a mouse handler (like the mouseMoved() method) versus
+ when inside draw(). Inside draw(), pmouseX is updated once each
+ frame, but inside mousePressed() and friends, it's updated each time
+ an event comes through. Be sure to use only one or the other type of
+ means for tracking pmouseX and pmouseY within your sketch, otherwise
+ you're gonna run into trouble.
+
+
+
+
+
+
+dmouseX
+
+int dmouseX
+
+
previous mouseX/Y for the draw loop, separated out because this is
+ separate from the pmouseX/Y when inside the mouse event handlers.
+
+
+
+
+
+
+dmouseY
+
+int dmouseY
+
+
previous mouseX/Y for the draw loop, separated out because this is
+ separate from the pmouseX/Y when inside the mouse event handlers.
+
+
+
+
+
+
+emouseX
+
+int emouseX
+
+
pmouseX/Y for the event handlers (mousePressed(), mouseDragged() etc)
+ these are different because mouse events are queued to the end of
+ draw, so the previous position has to be updated on each event,
+ as opposed to the pmouseX/Y that's used inside draw, which is expected
+ to be updated once per trip through draw().
+
+
+
+
+
+
+emouseY
+
+int emouseY
+
+
pmouseX/Y for the event handlers (mousePressed(), mouseDragged() etc)
+ these are different because mouse events are queued to the end of
+ draw, so the previous position has to be updated on each event,
+ as opposed to the pmouseX/Y that's used inside draw, which is expected
+ to be updated once per trip through draw().
+
+
+
+
+
+
+firstMouse
+
+boolean firstMouse
+
+
Used to set pmouseX/Y to mouseX/Y the first time mouseX/Y are used,
+ otherwise pmouseX/Y are always zero, causing a nasty jump.
+
+ Just using (frameCount == 0) won't work since mouseXxxxx()
+ may not be called until a couple frames into things.
+
+
+
+
+
+
+mouseButton
+
+int mouseButton
+
+
Last mouse button pressed, one of LEFT, CENTER, or RIGHT.
+
+ If running on Mac OS, a ctrl-click will be interpreted as
+ the righthand mouse button (unlike Java, which reports it as
+ the left mouse).
+
+
+
+
+
+
+mousePressed
+
+boolean mousePressed
+
+
+
+
+
+
+mouseEvent
+
+java.awt.event.MouseEvent mouseEvent
+
+
+
+
+
+
+key
+
+char key
+
+
Last key pressed.
+
+ If it's a coded key, i.e. UP/DOWN/CTRL/SHIFT/ALT,
+ this will be set to CODED (0xffff or 65535).
+
+
+
+
+
+
+keyCode
+
+int keyCode
+
+
When "key" is set to CODED, this will contain a Java key code.
+
+ For the arrow keys, keyCode will be one of UP, DOWN, LEFT and RIGHT.
+ Also available are ALT, CONTROL and SHIFT. A full set of constants
+ can be obtained from java.awt.event.KeyEvent, from the VK_XXXX variables.
+
+
+
+
+
+
+keyPressed
+
+boolean keyPressed
+
+
true if the mouse is currently pressed.
+
+
+
+
+
+
+keyEvent
+
+java.awt.event.KeyEvent keyEvent
+
+
the last KeyEvent object passed into a mouse function.
+
+
+
+
+
+
+focused
+
+boolean focused
+
+
Gets set to true/false as the applet gains/loses focus.
+
+
+
+
+
+
+online
+
+boolean online
+
+
true if the applet is online.
+
+ This can be used to test how the applet should behave
+ since online situations are different (no file writing, etc).
+
+
+
+
+
+
+millisOffset
+
+long millisOffset
+
+
Time in milliseconds when the applet was started.
+
+ Used by the millis() function.
+
+
+
+
+
+
+frameRate
+
+float frameRate
+
+
The current value of frames per second.
+
+ The initial value will be 10 fps, and will be updated with each
+ frame thereafter. The value is not instantaneous (since that
+ wouldn't be very useful since it would jump around so much),
+ but is instead averaged (integrated) over several frames.
+ As such, this value won't be valid until after 5-10 frames.
+
+
+
+
+
+
+frameRateLastNanos
+
+long frameRateLastNanos
+
+
Last time in nanoseconds that frameRate was checked
+
+
+
+
+
+
+frameRateTarget
+
+float frameRateTarget
+
+
As of release 0116, frameRate(60) is called as a default
+
+
+
+
+
+
+frameRatePeriod
+
+long frameRatePeriod
+
+
+
+
+
+
+looping
+
+boolean looping
+
+
+
+
+
+
+redraw
+
+boolean redraw
+
+
flag set to true when a redraw is asked for by the user
+
+
+
+
+
+
+frameCount
+
+int frameCount
+
+
How many frames have been displayed since the applet started.
+
+ This value is read-only do not attempt to set it,
+ otherwise bad things will happen.
+
+ Inside setup(), frameCount is 0.
+ For the first iteration of draw(), frameCount will equal 1.
+
+
+
+
+
+
+finished
+
+boolean finished
+
+
true if this applet has had it.
+
+
+
+
+
+
+exitCalled
+
+boolean exitCalled
+
+
true if exit() has been called so that things shut down
+ once the main thread kicks off.
+
By trial and error, four image loading threads seem to work best when
+ loading images from online. This is consistent with the number of open
+ connections that web browsers will maintain. The variable is made public
+ (however no accessor has been added since it's esoteric) if you really
+ want to have control over the value used. For instance, when loading local
+ files, it might be better to only have a single thread (or two) loading
+ images so that you're disk isn't simply jumping around.
+
+This class provides TokenStreamHiddenTokenFilters with the concept of
+ tokens which can be copied so that they are seen by both the hidden token
+ stream as well as the parser itself. This is useful when one wants to use
+ an existing parser (like the Java parser included with ANTLR) that throws
+ away some tokens to create a parse tree which can be used to spit out
+ a copy of the code with only minor modifications.
+
+ This code is partially derived from the public domain ANLTR TokenStream
+
Indicate that all tokens of type tokenType should be copied. The copy
+ is put in the stream of hidden tokens, and the original is returned in the
+ stream of normal tokens.
+
+
+
+
+
+
Parameters:
tokenType - integer representing the token type to copied
Return the next monitored token.
+ Test the token following the monitored token.
+ If following is another monitored token, save it
+ for the next invocation of nextToken (like a single
+ lookahead token) and return it then.
+ If following is unmonitored, nondiscarded (hidden)
+ channel token, add it to the monitored token.
+
+ Note: EOF must be a monitored Token.
+
+
+
Specified by:
nextToken in interface antlr.TokenStream
Overrides:
nextToken in class antlr.TokenStreamHiddenTokenFilter
+ Run 'java Main [-showtree] directory-full-of-java-files'
+
+ [The -showtree option pops up a Swing frame that shows
+ the AST constructed from the parser.]
+
+ Run 'java Main '
+
+ Contributing authors:
+ John Mitchell johnm@non.net
+ Terence Parr parrt@magelang.com
+ John Lilley jlilley@empathy.com
+ Scott Stanchfield thetick@magelang.com
+ Markus Mohnen mohnen@informatik.rwth-aachen.de
+ Peter Williams pete.williams@sun.com
+ Allan Jacobs Allan.Jacobs@eng.sun.com
+ Steve Messick messick@redhills.com
+ John Pybus john@pybus.org
+
+ Version 1.00 December 9, 1997 -- initial release
+ Version 1.01 December 10, 1997
+ fixed bug in octal def (0..7 not 0..8)
+ Version 1.10 August 1998 (parrt)
+ added tree construction
+ fixed definition of WS,comments for mac,pc,unix newlines
+ added unary plus
+ Version 1.11 (Nov 20, 1998)
+ Added "shutup" option to turn off last ambig warning.
+ Fixed inner class def to allow named class defs as statements
+ synchronized requires compound not simple statement
+ add [] after builtInType DOT class in primaryExpression
+ "const" is reserved but not valid..removed from modifiers
+ Version 1.12 (Feb 2, 1999)
+ Changed LITERAL_xxx to xxx in tree grammar.
+ Updated java.g to use tokens {...} now for 2.6.0 (new feature).
+
+ Version 1.13 (Apr 23, 1999)
+ Didn't have (stat)? for else clause in tree parser.
+ Didn't gen ASTs for interface extends. Updated tree parser too.
+ Updated to 2.6.0.
+ Version 1.14 (Jun 20, 1999)
+ Allowed final/abstract on local classes.
+ Removed local interfaces from methods
+ Put instanceof precedence where it belongs...in relationalExpr
+ It also had expr not type as arg; fixed it.
+ Missing ! on SEMI in classBlock
+ fixed: (expr) + "string" was parsed incorrectly (+ as unary plus).
+ fixed: didn't like Object[].class in parser or tree parser
+ Version 1.15 (Jun 26, 1999)
+ Screwed up rule with instanceof in it. :( Fixed.
+ Tree parser didn't like (expr).something; fixed.
+ Allowed multiple inheritance in tree grammar. oops.
+ Version 1.16 (August 22, 1999)
+ Extending an interface built a wacky tree: had extra EXTENDS.
+ Tree grammar didn't allow multiple superinterfaces.
+ Tree grammar didn't allow empty var initializer: {}
+ Version 1.17 (October 12, 1999)
+ ESC lexer rule allowed 399 max not 377 max.
+ java.tree.g didn't handle the expression of synchronized
+ statements.
+ Version 1.18 (August 12, 2001)
+ Terence updated to Java 2 Version 1.3 by
+ observing/combining work of Allan Jacobs and Steve
+ Messick. Handles 1.3 src. Summary:
+ o primary didn't include boolean.class kind of thing
+ o constructor calls parsed explicitly now:
+ see explicitConstructorInvocation
+ o add strictfp modifier
+ o missing objBlock after new expression in tree grammar
+ o merged local class definition alternatives, moved after declaration
+ o fixed problem with ClassName.super.field
+ o reordered some alternatives to make things more efficient
+ o long and double constants were not differentiated from int/float
+ o whitespace rule was inefficient: matched only one char
+ o add an examples directory with some nasty 1.3 cases
+ o made Main.java use buffered IO and a Reader for Unicode support
+ o supports UNICODE?
+ Using Unicode charVocabulay makes code file big, but only
+ in the bitsets at the end. I need to make ANTLR generate
+ unicode bitsets more efficiently.
+ Version 1.19 (April 25, 2002)
+ Terence added in nice fixes by John Pybus concerning floating
+ constants and problems with super() calls. John did a nice
+ reorg of the primary/postfix expression stuff to read better
+ and makes f.g.super() parse properly (it was METHOD_CALL not
+ a SUPER_CTOR_CALL). Also:
+
+ o "finally" clause was a root...made it a child of "try"
+ o Added stuff for asserts too for Java 1.4, but *commented out*
+ as it is not backward compatible.
+
+ Version 1.20 (October 27, 2002)
+
+ Terence ended up reorging John Pybus' stuff to
+ remove some nondeterminisms and some syntactic predicates.
+ Note that the grammar is stricter now; e.g., this(...) must
+ be the first statement.
+
+ Trinary ?: operator wasn't working as array name:
+ (isBig ? bigDigits : digits)[i];
+
+ Checked parser/tree parser on source for
+ Resin-2.0.5, jive-2.1.1, jdk 1.3.1, Lucene, antlr 2.7.2a4,
+ and the 110k-line jGuru server source.
+
+ This grammar is in the PUBLIC DOMAIN
+
declaration()
+
+
+ A declaration is the creation of a reference or primitive-type variable
+ Create a separate Type/Var tree for each var in the var list.
This class provides TokenStreamHiddenTokenFilters with the concept of
+ tokens which can be copied so that they are seen by both the hidden token
+ stream as well as the parser itself.
+This API (Application Programming Interface) document has pages corresponding to the items in the navigation bar, described as follows.
+Overview
+
+
+
+The Overview page is the front page of this API document and provides a list of all packages with a summary for each. This page can also contain an overall description of the set of packages.
+
+Package
+
+
+
+Each package has a page that contains a list of its classes and interfaces, with a summary for each. This page can contain four categories:
+
Interfaces (italic)
Classes
Enums
Exceptions
Errors
Annotation Types
+
+
+Class/Interface
+
+
+
+Each class, interface, nested class and nested interface has its own separate page. Each of these pages has three sections consisting of a class/interface description, summary tables, and detailed member descriptions:
+
Class inheritance diagram
Direct Subclasses
All Known Subinterfaces
All Known Implementing Classes
Class/interface declaration
Class/interface description
+
+
Nested Class Summary
Field Summary
Constructor Summary
Method Summary
+
+
Field Detail
Constructor Detail
Method Detail
+Each summary entry contains the first sentence from the detailed description for that item. The summary entries are alphabetical, while the detailed descriptions are in the order they appear in the source code. This preserves the logical groupings established by the programmer.
+
+
+Annotation Type
+
+
+
+Each annotation type has its own separate page with the following sections:
+
Annotation Type declaration
Annotation Type description
Required Element Summary
Optional Element Summary
Element Detail
+
+
+
+Enum
+
+
+
+Each enum has its own separate page with the following sections:
+
Enum declaration
Enum description
Enum Constant Summary
Enum Constant Detail
+
+
+Tree (Class Hierarchy)
+
+There is a Class Hierarchy page for all packages, plus a hierarchy for each package. Each hierarchy page contains a list of classes and a list of interfaces. The classes are organized by inheritance structure starting with java.lang.Object. The interfaces do not inherit from java.lang.Object.
+
When viewing the Overview page, clicking on "Tree" displays the hierarchy for all packages.
When viewing a particular package, class or interface page, clicking "Tree" displays the hierarchy for only that package.
+
+
+Deprecated API
+
+The Deprecated API page lists all of the API that have been deprecated. A deprecated API is not recommended for use, generally due to improvements, and a replacement API is usually given. Deprecated APIs may be removed in future implementations.
+
+Index
+
+The Index contains an alphabetic list of all classes, interfaces, constructors, methods, and fields.
+
+Prev/Next
+These links take you to the next or previous class, interface, package, or related page.
+Frames/No Frames
+These links show and hide the HTML frames. All pages are available with or without frames.
+
+
+Serialized Form
+Each serializable or externalizable class has a description of its serialization fields and methods. This information is of interest to re-implementors, not to developers using the API. While there is no link in the navigation bar, you can get to this information by going to any serialized class and clicking "Serialized Form" in the "See also" section of the class description.
+
If 'name' is null or the empty string, it won't set a specific
+ device, which means that QuickTime will use that last device
+ used by a QuickTime application.
+
Create a .vlw font on the fly from either a font name that's
+ installed on the system, or from a .ttf or .otf that's inside
+ the data folder of this sketch.
+
Preferred method of creating new PImage objects, ensures that a
+ reference to the parent PApplet is included, which makes save() work
+ without needing an absolute path.
+
Called by the browser or applet viewer to inform this applet
+ that it is being reclaimed and that it should destroy
+ any resources that it has allocated.
+
Creates a new window with the formated (YaBB tags) sketchcode
+ from the actual Processing Tab ready to send to the processing discourse
+ web (copy & paste)
+
Returns the offset of the bracket matching the one at the
+ specified offset of the document, or -1 if the bracket is
+ unmatched (or if the character is not a bracket).
+
Overriding keyXxxxx(KeyEvent e) functions will cause the 'key',
+ 'keyCode', and 'keyEvent' variables to no longer work;
+ key events will no longer be queued until the end of draw();
+ and the keyPressed(), keyReleased() and keyTyped() methods
+ will no longer be called.
+
If you override this or any function that takes a "MouseEvent e"
+ without calling its super.mouseXxxx() then mouseX, mouseY,
+ mousePressed, and mouseEvent will no longer be set.
+
number format signed (or space)
+ Formats a number but leaves a blank space in the front
+ when it's positive so that it can be properly aligned with
+ numbers that have a negative sign in front of them.
+
Implements the cross-platform headache of opening URLs
+ TODO This code should be replaced by PApplet.link(),
+ however that's not a static method (because it requires
+ an AppletContext when used as an applet), so it's mildly
+ trickier than just removing this method.
+
A classpath, separated by the path separator, will contain
+ a series of .jar/.zip files or directories containing .class
+ files, or containing subdirectories that have .class files.
+
Recursively remove all files within a directory,
+ used with removeDir(), or when the contents of a dir
+ should be removed, but not the directory itself.
+
Given an x and y coordinate, returns the x position of where
+ that point would be placed on screen, once affected by translate(),
+ scale(), or any other transformations.
+
Given an x and y coordinate, returns the y position of where
+ that point would be placed on screen, once affected by translate(),
+ scale(), or any other transformations.
+
Called in response to a resize event, handles setting the
+ new width and height internally, as well as re-allocating
+ the pixel buffer for the new size.
+
Called in response to a resize event, handles setting the
+ new width and height internally, as well as re-allocating
+ the pixel buffer for the new size.
+
If this client property is set to Boolean.TRUE on the text area,
+ the home/end keys will support 'smart' BRIEF-like behaviour
+ (one press = start/end of line, two presses = start/end of
+ viewscreen, three presses = start/end of document).
+
Sets the text rendering/placement to be either SCREEN (direct
+ to the screen, exact coordinates, only use the font's original size)
+ or MODEL (the default, where text is manipulated by translate() and
+ can have a textSize).
+
This class provides TokenStreamHiddenTokenFilters with the concept of
+ tokens which can be copied so that they are seen by both the hidden token
+ stream as well as the parser itself.
+This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client.
+
+Link toNon-frame version.
+
+The base class for the main processing application.
+ Primary role of this class is for platform identification and
+ general interaction with the system (launching URLs, loading
+ files and images, etc) that comes from that.
+
countLines(java.lang.String what)
+
+
+ Get the number of lines in a file by counting the number of newline
+ characters inside a String (and adding 1).
+
+
+
+static java.io.File
+
createTempFolder(java.lang.String name)
+
+
+ Get the path to the platform's temporary folder, by creating
+ a temporary temporary file and getting its parent folder.
listFiles(java.lang.String path,
+ boolean relative)
+
+
+ Recursively creates a list of all files within the specified folder,
+ and returns a list of their relative paths.
+
+
+
+static byte[]
+
loadBytesRaw(java.io.File file)
+
+
+ Same as PApplet.loadBytes(), however never does gzip decoding.
+
+
+
+static java.lang.String
+
loadFile(java.io.File file)
+
+
+ Grab the contents of a file as a string.
openFolder(java.io.File file)
+
+
+ Implements the other cross-platform headache of opening
+ a folder in the machine's native file browser.
+
+
+
+static void
+
openURL(java.lang.String url)
+
+
+ Implements the cross-platform headache of opening URLs
+ TODO This code should be replaced by PApplet.link(),
+ however that's not a static method (because it requires
+ an AppletContext when used as an applet), so it's mildly
+ trickier than just removing this method.
registerWindowCloseKeys(javax.swing.JRootPane root,
+ java.awt.event.ActionListener disposer)
+
+
+ Registers key events for a Ctrl-W and ESC with an ActionListener
+ that will take care of disposing the window.
+
+
+
+static void
+
removeDescendants(java.io.File dir)
+
+
+ Recursively remove all files within a directory,
+ used with removeDir(), or when the contents of a dir
+ should be removed, but not the directory itself.
+
+
+
+static void
+
removeDir(java.io.File dir)
+
+
+ Remove all files in a directory and the directory itself.
+
+
+
+static void
+
saveFile(java.lang.String str,
+ java.io.File file)
+
+
+ Spew the contents of a String object out to a file.
+
+
+
+static java.io.File
+
selectFolder(java.lang.String prompt,
+ java.io.File folder,
+ java.awt.Frame frame)
+
+
+ Prompt for a fodler and return it as a File object (or null).
+
+
+
+static void
+
setIcon(java.awt.Frame frame)
+
+
+ Give this Frame a Processing icon.
Convenience method to get a File object for the specified filename inside
+ the settings folder.
+ For now, only used by Preferences to get the preferences.txt file.
+
+
+
Parameters:
filename - A file inside the settings folder.
+
Returns:
filename wrapped as a File object inside the settings folder
Get the path to the platform's temporary folder, by creating
+ a temporary temporary file and getting its parent folder.
+
+ Modified for revision 0094 to actually make the folder randomized
+ to avoid conflicts in multi-user environments. (Bug 177)
+
Implements the cross-platform headache of opening URLs
+ TODO This code should be replaced by PApplet.link(),
+ however that's not a static method (because it requires
+ an AppletContext when used as an applet), so it's mildly
+ trickier than just removing this method.
+
+
+
+
+
+
+
+
+openFolder
+
+public static void openFolder(java.io.File file)
+
+
Implements the other cross-platform headache of opening
+ a folder in the machine's native file browser.
+
Prompt for a fodler and return it as a File object (or null).
+ Implementation for choosing directories that handles both the
+ Mac OS X hack to allow the native AWT file dialog, or uses
+ the JFileChooser on other platforms. Mac AWT trick obtained from
+ this post
+ on the OS X Java dev archive which explains the cryptic note in
+ Apple's Java 1.4 release docs about the special System property.
+
Show an error message that's actually fatal to the program.
+ This is an error that can't be recovered. Use showWarning()
+ for errors that allow P5 to continue running.
+
Copy a folder from one place to another. This ignores all dot files and
+ folders found in the source directory, to avoid copying silly .DS_Store
+ files and potentially troublesome .svn folders.
+
+
+
+
Throws:
+
java.io.IOException
+
+
+
+
+
+removeDir
+
+public static void removeDir(java.io.File dir)
+
+
Remove all files in a directory and the directory itself.
+
Recursively remove all files within a directory,
+ used with removeDir(), or when the contents of a dir
+ should be removed, but not the directory itself.
+ (i.e. when cleaning temp files from lib/build)
+
+
+
+
+
+
+
+
+calcFolderSize
+
+public static int calcFolderSize(java.io.File folder)
+
+
Calculate the size of the contents of a folder.
+ Used to determine whether sketches are empty or not.
+ Note that the function calls itself recursively.
+
Recursively creates a list of all files within the specified folder,
+ and returns a list of their relative paths.
+ Ignores any files/folders prefixed with a dot.
+
+Class to handle running Processing from the command line.
+
+ --help Show the help text.
+
+ --sketch=<name&rt; Specify the sketch folder (required)
+ --output=<name&rt; Specify the output folder (required and
+ cannot be the same as the sketch folder.)
+
+ --preprocess Preprocess a sketch into .java files.
+ --build Preprocess and compile a sketch into .class files.
+ --run Preprocess, compile, and run a sketch.
+ --present Preprocess, compile, and run a sketch full screen.
+
+ --export-applet Export an applet.
+ --export-application Export an application.
+ --platform Specify the platform (export to application only).
+ Should be one of 'windows', 'macosx', or 'linux'.
+
+ --preferences=<file&rt; Specify a preferences file to use (optional).
+
+
+ To build the command line version, first build for your platform,
+ then cd to processing/build/cmd and type 'dist.sh'. This will create a
+ usable installation plus a zip file of the same.
+
newJMenuItem(java.lang.String title,
+ int what)
+
+
+ A software engineer, somewhere, needs to have his abstraction
+ taken away.
+
+
+
+static javax.swing.JMenuItem
+
newJMenuItemAlt(java.lang.String title,
+ int what)
+
+
+ Same as newJMenuItem(), but adds the ALT (on Linux and Windows)
+ or OPTION (on Mac OS X) key as a modifier.
+
+
+
+static javax.swing.JMenuItem
+
newJMenuItemShift(java.lang.String title,
+ int what)
+
+
+ Like newJMenuItem() but adds shift as a modifier for the key command.
+
+
+
+ void
+
setLineText(int line,
+ java.lang.String what)
+
+
+ Replace the text on a specified line.
Hack for #@#)$(* Mac OS X 10.2.
+
+ This appears to only be required on OS X 10.2, and is not
+ even being called on later versions of OS X or Windows.
+
+
+
Overrides:
getMinimumSize in class java.awt.Container
+
+
+
+
+
+
+
+
+newJMenuItem
+
+public static javax.swing.JMenuItem newJMenuItem(java.lang.String title,
+ int what)
+
+
A software engineer, somewhere, needs to have his abstraction
+ taken away. In some countries they jail or beat people for writing
+ the sort of API that would require a five line helper function
+ just to set the command key for a menu item.
+
+
+
+
+
+
+
+
+
+
+
+newJMenuItemShift
+
+public static javax.swing.JMenuItem newJMenuItemShift(java.lang.String title,
+ int what)
+
+
Like newJMenuItem() but adds shift as a modifier for the key command.
+
+
+
+
+
+
+
+
+
+
+
+newJMenuItemAlt
+
+public static javax.swing.JMenuItem newJMenuItemAlt(java.lang.String title,
+ int what)
+
+
Same as newJMenuItem(), but adds the ALT (on Linux and Windows)
+ or OPTION (on Mac OS X) key as a modifier.
+
Get the JEditTextArea object for use (not recommended). This should only
+ be used in obscure cases that really need to hack the internals of the
+ JEditTextArea. Most tools should only interface via the get/set functions
+ found in this class. This will maintain compatibility with future releases,
+ which will not use JEditTextArea.
+
+
+
+
+
+
+
+
+
+
+
+getText
+
+public java.lang.String getText()
+
+
Get the contents of the current buffer. Used by the Sketch class.
+
+
+
+
+
+
+
+
+
+
+
+getText
+
+public java.lang.String getText(int start,
+ int stop)
+
+
Get a range of text from the current buffer.
+
+
+
+
+
+
+
+
+
+
+
+setText
+
+public void setText(java.lang.String what)
+
+
Replace the entire contents of the front-most tab.
+
+
+
+
+
+
+
+
+
+
+
+insertText
+
+public void insertText(java.lang.String what)
+
+
+
+
+
+
+
+
+
+
+
+getSelectedText
+
+public java.lang.String getSelectedText()
+
+
Called to update the text but not switch to a different set of code
+ (which would affect the undo manager).
+
Get the position (character offset) of the caret. With text selected,
+ this will be the last character actually selected, no matter the direction
+ of the selection. That is, if the user clicks and drags to select lines
+ 7 up to 4, then the caret position will be somewhere on line four.
+
+
+
+
+
+
+
+
+
+
+
+isSelectionActive
+
+public boolean isSelectionActive()
+
+
True if some text is currently selected.
+
+
+
+
+
+
+
+
+
+
+
+getSelectionStart
+
+public int getSelectionStart()
+
+
Get the beginning point of the current selection.
+
Get character offset for the start of a given line of text.
+
+
+
+
+
+
+
+
+
+
+
+getLineStopOffset
+
+public int getLineStopOffset(int line)
+
+
Get character offset for end of a given line of text.
+
+
+
+
+
+
+
+
+
+
+
+getLineCount
+
+public int getLineCount()
+
+
Get the number of lines in the currently displayed buffer.
+
+
+
+
+
+
+
+
+
+
+
+startCompoundEdit
+
+public void startCompoundEdit()
+
+
Use before a manipulating text to group editing operations together as a
+ single undo. Use stopCompoundEdit() once finished.
+
+
+
+
+
+
+
+
+
+
+
+stopCompoundEdit
+
+public void stopCompoundEdit()
+
+
Use with startCompoundEdit() to group edit operations in a single undo.
+
+
+
+
+
+
+
+
+
+
+
+getScrollPosition
+
+public int getScrollPosition()
+
+
+
+
+
+
+
+
+
+
+
+handleCut
+
+public void handleCut()
+
+
Implements Edit → Cut.
+
+
+
+
+
+
+
+
+
+
+
+handleCopy
+
+public void handleCopy()
+
+
Implements Edit → Copy.
+
+
+
+
+
+
+
+
+
+
+
+handlePaste
+
+public void handlePaste()
+
+
Implements Edit → Paste.
+
+
+
+
+
+
+
+
+
+
+
+handleSelectAll
+
+public void handleSelectAll()
+
+
Implements Edit → Select All.
+
+
+
+
+
+
+
+
+
+
+
+handleRun
+
+public void handleRun(boolean present)
+
+
Implements Sketch → Run.
+
+
+
+
+
+
Parameters:
present - Set true to run in full screen (present mode).
+
+
+
+
+
+setSketchLocation
+
+public void setSketchLocation(java.awt.Point p)
+
+
Set the location of the sketch run window. Used by Runner to update the
+ Editor about window drag events while the sketch is running.
+
+
+
+
+
+
+
+
+
+
+
+getSketchLocation
+
+public java.awt.Point getSketchLocation()
+
+
Get the last location of the sketch's run window. Used by Runner to make
+ the window show up in the same location as when it was last closed.
+
+
+
+
+
+
+
+
+
+
+
+handleStop
+
+public void handleStop()
+
+
Implements Sketch → Stop, or pressing Stop on the toolbar.
+
+
+
+
+
+
+
+
+
+
+
+internalRunnerClosed
+
+public void internalRunnerClosed()
+
+
Called by Runner to notify that the sketch has stopped running.
+ Tools should not call this function, use handleStop() instead.
+
+
+
+
+
+
+
+
+
+
+
+internalCloseRunner
+
+public void internalCloseRunner()
+
+
Handle internal shutdown of the runner.
+
+
+
+
+
+
+
+
+
+
+
+handleSave
+
+public boolean handleSave(boolean immediately)
+
+
Actually handle the save command. If 'immediately' is set to false,
+ this will happen in another thread so that the message area
+ will update and the save button will stay highlighted while the
+ save is happening. If 'immediately' is true, then it will happen
+ immediately. This is used during a quit, because invokeLater()
+ won't run properly while a quit is happening. This fixes
+ Bug 276.
+
+
+
+
+
+
+
+
+
+
+
+handleSaveAs
+
+public boolean handleSaveAs()
+
+
+
+
+
+
+
+
+
+
+
+handleExport
+
+public void handleExport()
+
+
Called by Sketch → Export.
+ Handles calling the export() function on sketch, and
+ queues all the gui status stuff that comes along with it.
+
+ Made synchronized to (hopefully) avoid problems of people
+ hitting export twice, quickly, and horking things up.
+
+Message console that sits below the editing area.
+
+ Debugging this class is tricky... If it's throwing exceptions,
+ don't take over System.err, and debug while watching just System.out
+ or just write println() or whatever directly to systemOut or systemErr.
+
Close the streams so that the temporary files can be deleted.
+
+ File.deleteOnExit() cannot be used because the stdout and stderr
+ files are inside a folder, and have to be deleted before the
+ folder itself is deleted, which can't be guaranteed when using
+ the deleteOnExit() method.
+
+
+
+
+
+
+
+
+write
+
+public void write(byte[] b,
+ int offset,
+ int length,
+ boolean err)
+Filters key events for tab expansion/indent/etc.
+
+ For version 0099, some changes have been made to make the indents
+ smarter. There are still issues though:
+ + indent happens when it picks up a curly brace on the previous line,
+ but not if there's a blank line between them.
+ + It also doesn't handle single indent situations where a brace
+ isn't used (i.e. an if statement or for loop that's a single line).
+ It shouldn't actually be using braces.
+ Solving these issues, however, would probably best be done by a
+ smarter parser/formatter, rather than continuing to hack this class.
+
Intercepts key pressed events for JEditTextArea.
+
+ Called by JEditTextArea inside processKeyEvent(). Note that this
+ won't intercept actual characters, because those are fired on
+ keyTyped().
+
+
+
+
Returns:
true if the event has been handled (to remove it from the queue)
+Find & Replace window for the Processing editor.
+
+ One major annoyance in this is that the window is re-created each time
+ that "Find" is called. This is because Mac OS X has a strange focus
+ issue with windows that are re-shown with setVisible() or show().
+ requestFocusInWindow() properly sets the focus to the find field,
+ however, just a short moment later, the focus is set to null. Even
+ trying to catch this scenario and request it again doesn't seem to work.
+ Most likely this is some annoyance buried deep in one of Apple's docs,
+ or in the doc for the focus stuff (I tend to think the former because
+ Windows doesn't seem to be quite so beligerent). Filed as
+ Bug 244
+ should anyone have clues about how to fix.
+
+Used by Base for platform-specific tweaking, for instance finding the
+ sketchbook location using the Windows registry, or OS X event handling.
+
+ The methods in this implementation are used by default, and can be
+ overridden by a subclass, if loaded by Base.main().
+
+ These methods throw vanilla-flavored Exceptions, so that error handling
+ occurs inside Base.
+
+ There is currently no mechanism for adding new platforms, as the setup is
+ not automated. We could use getProperty("os.arch") perhaps, but that's
+ debatable (could be upper/lowercase, have spaces, etc.. basically we don't
+ know if name is proper Java package syntax.)
+
Set the default L & F. While I enjoy the bounty of the sixteen possible
+ exception types that this UIManager method might throw, I feel that in
+ just this one particular case, I'm being spoiled by those engineers
+ at Sun, those Masters of the Abstractionverse. It leaves me feeling sad
+ and overweight. So instead, I'll pretend that I'm not offered eleven dozen
+ ways to report to the user exactly what went wrong, and I'll bundle them
+ all into a single catch-all "Exception". Because in the end, all I really
+ care about is whether things worked or not. And even then, I don't care.
+
+Storage class for user preferences and environment settings.
+
+ This class no longer uses the Properties class, since
+ properties files are iso8859-1, which is highly likely to
+ be a problem when trying to save sketch folders and locations.
+
+ The GUI portion in here is really ugly, as it uses exact layout. This was
+ done in frustration one evening (and pre-Swing), but that's long since past,
+ and it should all be moved to a proper swing layout like BoxLayout.
+
+ This is very poorly put together, that the preferences panel and the actual
+ preferences i/o is part of the same code. But there hasn't yet been a
+ compelling reason to bother with the separation aside from concern about
+ being lectured by strangers who feel that it doesn't look like what they
+ learned in CS class.
+
+ Would also be possible to change this to use the Java Preferences API.
+ Some useful articles
+ here and
+ here.
+ However, haven't implemented this yet for lack of time, but more
+ importantly, because it would entail writing to the registry (on Windows),
+ or an obscure file location (on Mac OS X) and make it far more difficult to
+ find the preferences to tweak them by hand (no! stay out of regedit!)
+ or to reset the preferences by simply deleting the preferences.txt file.
+
Standardized width for buttons. Mac OS X 10.3 wants 70 as its default,
+ Windows XP needs 66, and my Ubuntu machine needs 80+, so 80 seems proper.
+
+
+
+
+
+
+
+BUTTON_HEIGHT
+
+public static int BUTTON_HEIGHT
+
+
Standardized button height. Mac OS X 10.3 (Java 1.4) wants 29,
+ presumably because it now includes the blue border, where it didn't
+ in Java 1.3. Windows XP only wants 23 (not sure what default Linux
+ would be). Because of the disparity, on Mac OS X, it will be set
+ inside a static block.
+
+Stores information about files in the current sketch
+
+
+
+
+
+
+
+
+
+
+
+
+
+Constructor Summary
+
+
+
Sketch(Editor editor,
+ java.lang.String path)
+
+
+ path is location of the main .pde file, because this is also
+ simplest to use when opening the file from the finder/explorer.
+
+
+
+
+
+
+
+
+
+Method Summary
+
+
+
+ boolean
+
addFile(java.io.File sourceFile)
+
+
+ Add a file to the sketch.
+
+
+
+ java.lang.String
+
build(java.lang.String buildPath)
+
+
+ Preprocess and compile all the code for this sketch.
+
+
+
+static java.lang.String
+
checkName(java.lang.String origName)
+
+
+ Convert to sanitized name and alert the user
+ if changes were made.
+
+
+
+ boolean
+
exportApplet(java.lang.String appletPath)
+
+
+ Handle export to applet.
+
+
+
+ boolean
+
exportApplication(java.lang.String destPath,
+ int exportPlatform)
+
+
+ Export to application without GUI.
Prompt the user for a new file to the sketch, then call the
+ other addFile() function to actually add it.
+
+
+
+
+
+
+
+
+addFile
+
+public boolean addFile(java.io.File sourceFile)
+
+
Add a file to the sketch.
+
+ .pde or .java files will be added to the sketch folder.
+ .jar, .class, .dll, .jnilib, and .so files will all
+ be added to the "code" folder.
+ All other files will be added to the "data" folder.
+
+ If they don't exist already, the "code" or "data" folder
+ will be created.
+
+
Build all the code for this sketch.
+
+ In an advanced program, the returned class name could be different,
+ which is why the className is set based on the return value.
+ A compilation error will burp up a RunnerException.
+
+ Setting purty to 'true' will cause exception line numbers to be incorrect.
+ Unless you know the code compiles, you should first run the preprocessor
+ with purty set to false to make sure there are no errors, then once
+ successful, re-export with purty set to true.
+
+
+
Parameters:
buildPath - Location to copy all the .java files
+
Returns:
null if compilation failed, main class name if not
+
Preprocess and compile all the code for this sketch.
+
+ In an advanced program, the returned class name could be different,
+ which is why the className is set based on the return value.
+ A compilation error will burp up a RunnerException.
+
+
+
+
Returns:
null if compilation failed, main class name if not
+
Returns true if this is a read-only sketch. Used for the
+ examples directory, or when sketches are loaded from read-only
+ volumes or folders without appropriate permissions.
+
Produce a sanitized name that fits our standards for likely to work.
+
+ Java classes have a wider range of names that are technically allowed
+ (supposedly any Unicode name) than what we support. The reason for
+ going more narrow is to avoid situations with text encodings and
+ converting during the process of moving files between operating
+ systems, i.e. uploading from a Windows machine to a Linux server,
+ or reading a FAT32 partition in OS X and using a thumb drive.
+
+ This helper function replaces everything but A-Z, a-z, and 0-9 with
+ underscores. Also disallows starting the sketch name with a digit.
+
+Storage class for theme settings. This was separated from the Preferences
+ class for 1.0 so that the coloring wouldn't conflict with previous releases
+ and to make way for future ability to customize.
+
+Threaded class to check for updates in the background.
+
+ This is the class that handles the mind control and stuff for
+ spying on our users and stealing their personal information.
+ A random ID number is generated for each user, and hits the server
+ to check for updates. Also included is the operating system and
+ its version and the version of Java being used to run Processing.
+
+ The ID number also helps provide us a general idea of how many
+ people are using Processing, which helps us when writing grant
+ proposals and that kind of thing so that we can keep Processing free.
+
contentsToClassPath(java.io.File folder)
+
+
+ Given a folder, return a list of absolute paths to all jar or zip files
+ inside that folder, separated by pathSeparatorChar.
+
+
+
+static java.lang.String[]
+
packageListFromClassPath(java.lang.String path)
+
+
+ A classpath, separated by the path separator, will contain
+ a series of .jar/.zip files or directories containing .class
+ files, or containing subdirectories that have .class files.
Given a folder, return a list of absolute paths to all jar or zip files
+ inside that folder, separated by pathSeparatorChar.
+
+ This will prepend a colon (or whatever the path separator is)
+ so that it can be directly appended to another path string.
+
+ As of 0136, this will no longer add the root folder as well.
+
+ This function doesn't bother checking to see if there are any .class
+ files in the folder or within a subfolder.
+
A classpath, separated by the path separator, will contain
+ a series of .jar/.zip files or directories containing .class
+ files, or containing subdirectories that have .class files.
+
+Interface for dealing with parser/compiler output.
+
+ Different instances of MessageStream need to do different things with
+ messages. In particular, a stream instance used for parsing output from
+ the compiler compiler has to interpret its messages differently than one
+ parsing output from the runtime.
+
+ Classes which consume messages and do something with them
+ should implement this interface.
+
+Runs a compiled sketch. As of release 0136, all sketches are run externally
+ to the environment so that a debugging interface can be used. This opens up
+ future options for a decent debugger, but in the meantime fixes several
+ problems with output and error streams, messages getting lost on Mac OS X,
+ the run/stop buttons not working, libraries not shutting down, exceptions
+ not coming through, exceptions being printed twice, having to force quit
+ if you make a bad while() loop, and so on.
+
Set the default L & F. While I enjoy the bounty of the sixteen possible
+ exception types that this UIManager method might throw, I feel that in
+ just this one particular case, I'm being spoiled by those engineers
+ at Sun, those Masters of the Abstractionverse. It leaves me feeling sad
+ and overweight. So instead, I'll pretend that I'm not offered eleven dozen
+ ways to report to the user exactly what went wrong, and I'll bundle them
+ all into a single catch-all "Exception". Because in the end, all I really
+ care about is whether things worked or not. And even then, I don't care.
+
Set the default L & F. While I enjoy the bounty of the sixteen possible
+ exception types that this UIManager method might throw, I feel that in
+ just this one particular case, I'm being spoiled by those engineers
+ at Sun, those Masters of the Abstractionverse. It leaves me feeling sad
+ and overweight. So instead, I'll pretend that I'm not offered eleven dozen
+ ways to report to the user exactly what went wrong, and I'll bundle them
+ all into a single catch-all "Exception". Because in the end, all I really
+ care about is whether things worked or not. And even then, I don't care.
+
+Deal with issues related to thinking different. This handles the basic
+ Mac OS X menu commands (and apple events) for open, about, prefs, etc.
+
+ Based on OSXAdapter.java from Apple DTS.
+
+ As of 0140, this code need not be built on platforms other than OS X,
+ because of the new platform structure which isolates through reflection.
+
+PDEEmitter: A class that can take an ANTLR Java AST and produce
+ reasonably formatted Java code from it. To use it, create a
+ PDEEmitter object, call setOut() if you want to print to something
+ other than System.out, and then call print(), passing the
+ AST. Typically, the AST node that you pass would be the root of a
+ tree - the ROOT_ID node that represents a Java file.
+
+
+
+
+
+
+
+
+
+
+
+
+Field Summary
+
+
+
+
+
+
Fields inherited from interface processing.app.preproc.PdeTokenTypes
Print the given AST. Call this function to print your PDE code.
+
+ It works by making recursive calls to print children.
+ So the code below is one big "switch" statement on the passed AST type.
+
+Class that orchestrates preprocessing p5 syntax into straight Java.
+
+ Current Preprocessor Subsitutions:
+
+
any function not specified as being protected or private will
+ be made 'public'. this means that void setup() becomes
+ public void setup(). This is important to note when
+ coding with core.jar outside of the PDE.
+
compiler.substitute_floats (currently "substitute_f")
+ treat doubles as floats, i.e. 12.3 becomes 12.3f so that people
+ don't have to add f after their numbers all the time since it's
+ confusing for beginners.
+
compiler.enhanced_casting byte(), char(), int(), float()
+ works for casting. this is basic in the current implementation, but
+ should be expanded as described above. color() works similarly to int(),
+ however there is also a *function* called color(r, g, b) in p5.
+
compiler.color_datatype 'color' is aliased to 'int'
+ as a datatype to represent ARGB packed into a single int, commonly
+ used in p5 for pixels[] and other color operations. this is just a
+ search/replace type thing, and it can be used interchangeably with int.
+
compiler.web_colors (currently "inline_web_colors")
+ color c = #cc0080; should unpack to 0xffcc0080 (the ff at the top is
+ so that the color is opaque), which is just an int.
+
+ Other preprocessor functionality
+
+
detects what 'mode' the program is in: static (no function
+ brackets at all, just assumes everything is in draw), active
+ (setup plus draw or loop), and java mode (full java support).
+ http://processing.org/reference/environment/
+
+
+ The PDE Preprocessor is based on the Java Grammar that comes with
+ ANTLR 2.7.2. Moving it forward to a new version of the grammar
+ shouldn't be too difficult.
+
+ Here's some info about the various files in this directory:
+
+ java.g: this is the ANTLR grammar for Java 1.3/1.4 from the
+ ANTLR distribution. It is in the public domain. The only change to
+ this file from the original this file is the uncommenting of the
+ clauses required to support assert().
+
+ java.tree.g: this describes the Abstract Syntax Tree (AST)
+ generated by java.g. It is only here as a reference for coders hacking
+ on the preprocessor, it is not built or used at all. Note that pde.g
+ overrides some of the java.g rules so that in PDE ASTs, there are a
+ few minor differences. Also in the public domain.
+
+ pde.g: this is the grammar and lexer for the PDE language
+ itself. It subclasses the java.g grammar and lexer. There are a couple
+ of overrides to java.g that I hope to convince the ANTLR folks to fold
+ back into their grammar, but most of this file is highly specific to
+ PDE itself.
+ PdeEmitter.java: this class traverses the AST generated by
+ the PDE Recognizer, and emits it as Java code, doing any necessary
+ transformations along the way. It is based on JavaEmitter.java,
+ available from antlr.org, written by Andy Tripp ,
+ who has given permission for it to be distributed under the GPL.
+
+ ExtendedCommonASTWithHiddenTokens.java: this adds a necessary
+ initialize() method, as well as a number of methods to allow for XML
+ serialization of the parse tree in a such a way that the hidden tokens
+ are visible. Much of the code is taken from the original
+ CommonASTWithHiddenTokens class. I hope to convince the ANTLR folks
+ to fold these changes back into that class so that this file will be
+ unnecessary.
+
+ TokenStreamCopyingHiddenTokenFilter.java: this class provides
+ TokenStreamHiddenTokenFilters with the concept of tokens which can be
+ copied so that they are seen by both the hidden token stream as well
+ as the parser itself. This is useful when one wants to use an
+ existing parser (like the Java parser included with ANTLR) that throws
+ away some tokens to create a parse tree which can be used to spit out
+ a copy of the code with only minor modifications. Partially derived
+ from ANTLR code. I hope to convince the ANTLR folks to fold this
+ functionality back into ANTLR proper as well.
+
+ whitespace_test.pde: a torture test to ensure that the
+ preprocessor is correctly preserving whitespace, comments, and other
+ hidden tokens correctly. See the comments in the code for details about
+ how to run the test.
+
+ All other files in this directory are generated at build time by ANTLR
+ itself. The ANTLR manual goes into a fair amount of detail about the
+ what each type of file is for.
+
+
An abstract method that splits a line up into tokens. It
+ should parse the line, and call addToken() to
+ add syntax tokens to the token list. Then, it should return
+ the initial token type for the next line.
+
+ For example if the current line contains the start of a
+ multiline comment that doesn't end on that line, this method
+ should return the comment token type so that it continues on
+ the next line.
+
+
+
+
+
+
Parameters:
token - The initial token type for this line
line - The line to be tokenized
lineIndex - The index of the line in the document,
+ starting at 0
+
Adds a key binding to this input handler. The key binding is
+ a list of white space separated key strokes of the form
+ [modifiers+]key where modifier is C for Control, A for Alt,
+ or S for Shift, and key is either a character (a-z) or a field
+ name in the KeyEvent class prefixed with VK_ (e.g., BACK_SPACE)
+
Converts a string to a keystroke. The string should be of the
+ form modifiers+shortcut where modifiers
+ is any combination of A for Alt, C for Control, S for Shift
+ or M for Meta, and shortcut is either a single character,
+ or a keycode name from the KeyEvent class, without
+ the VK_ prefix.
+
+
+
Parameters:
keyStroke - A string description of the key stroke
+An input handler converts the user's key strokes into concrete actions.
+ It also takes care of macro recording and action repetition.
+
+ This class provides all the necessary support code for an input
+ handler, but doesn't actually do any key binding logic. It is up
+ to the implementations of this class to do so.
+
SMART_HOME_END_PROPERTY
+
+
+ If this client property is set to Boolean.TRUE on the text area,
+ the home/end keys will support 'smart' BRIEF-like behaviour
+ (one press = start/end of line, two presses = start/end of
+ viewscreen, three presses = start/end of document).
getTextArea(java.util.EventObject evt)
+
+
+ Returns the text area that fired the specified event.
+
+
+
+ void
+
grabNextKeyStroke(java.awt.event.ActionListener listener)
+
+
+ Grabs the next key typed event and invokes the specified
+ action with the key as a the action command.
+public static final java.lang.String SMART_HOME_END_PROPERTY
+
+
If this client property is set to Boolean.TRUE on the text area,
+ the home/end keys will support 'smart' BRIEF-like behaviour
+ (one press = start/end of line, two presses = start/end of
+ viewscreen, three presses = start/end of document). By default,
+ this property is not set.
+
Returns the name of the specified text area action.
+
+
+
Parameters:
listener - The action
+
+
+
+
+
+getActions
+
+public static java.util.Enumeration getActions()
+
+
Returns an enumeration of all available actions.
+
+
+
+
+
+
+
+
+addDefaultKeyBindings
+
+public abstract void addDefaultKeyBindings()
+
+
Adds the default key bindings to this input handler.
+ This should not be called in the constructor of this
+ input handler, because applications might load the
+ key bindings from a file, etc.
+
Grabs the next key typed event and invokes the specified
+ action with the key as a the action command.
+
+
+
+
+
+
+
+
+isRepeatEnabled
+
+public boolean isRepeatEnabled()
+
+
Returns if repeating is enabled. When repeating is enabled,
+ actions will be executed multiple times. This is usually
+ invoked with a special key stroke in the input handler.
+
+
+
+
+
+
+
+
+setRepeatEnabled
+
+public void setRepeatEnabled(boolean repeat)
+
+
Enables repeating. When repeating is enabled, actions will be
+ executed multiple times. Once repeating is enabled, the input
+ handler should read a number from the keyboard.
+
+
+
+
+
+
+
+
+getRepeatCount
+
+public int getRepeatCount()
+
+
Returns the number of times the next action will be repeated.
+
+
+
+
+
+
+
+
+setRepeatCount
+
+public void setRepeatCount(int repeatCount)
+
+
Sets the number of times the next action will be repeated.
+
+jEdit's text area component. It is more suited for editing program
+ source code than JEditorPane, because it drops the unnecessary features
+ (images, variable-width lines, and so on) and adds a whole bunch of
+ useful goodies such as:
+
+
More flexible key binding scheme
+
Supports macro recorders
+
Rectangular selection
+
Bracket highlighting
+
Syntax highlighting
+
Command repetition
+
Block caret can be enabled
+
+ It is also faster and doesn't have as many problems. It can be used
+ in other applications; the only other part of jEdit it depends on is
+ the syntax package.
+
+ To use it in your app, treat it like any other component, for example:
+
JEditTextArea ta = new JEditTextArea();
+ ta.setTokenMarker(new JavaTokenMarker());
+ ta.setText("public class Test {\n"
+ + " public static void main(String[] args) {\n"
+ + " System.out.println(\"Hello World\");\n"
+ + " }\n"
+ + "}");
isSelectionRectangular()
+
+
+ Returns true if the selection is rectangular, false otherwise.
+
+
+
+ int
+
lineToY(int line)
+
+
+ Converts a line index to a y co-ordinate.
+
+
+
+ int
+
offsetToX(int line,
+ int offset)
+
+
+ Converts an offset in a line into an x co-ordinate.
+
+
+
+ void
+
overwriteSetSelectedText(java.lang.String str)
+
+
+ Similar to setSelectedText(), but overstrikes the
+ appropriate number of characters if overwrite mode is enabled.
+
+
+
+ void
+
paste()
+
+
+ Inserts the clipboard contents into the text.
setDocument(SyntaxDocument document,
+ int start,
+ int stop,
+ int scroll)
+
+
+ Set document with a twist, includes the old caret
+ and scroll positions, added for p5.
+
+
+
+ void
+
setEditable(boolean editable)
+
+
+ Sets if this component is editable.
+
+
+
+ void
+
setElectricScroll(int electricScroll)
+
+
+ Sets the number of lines from the top and bottom of the text
+ area that are always visible
+
+
+
+ void
+
setFirstLine(int firstLine)
+
+
+ Sets the line displayed at the text area's origin without
+ updating the scroll bars.
+
+
+
+ void
+
setHorizontalOffset(int horizontalOffset)
+
+
+ Sets the horizontal offset of drawn lines.
caretVisible - True if the caret should be visible, false
+ otherwise
+
+
+
+
+
+blinkCaret
+
+public final void blinkCaret()
+
+
Blinks the caret.
+
+
+
+
+
+
+
+
+getElectricScroll
+
+public final int getElectricScroll()
+
+
Returns the number of lines from the top and button of the
+ text area that are always visible.
+
+
+
+
+
+
+
+
+setElectricScroll
+
+public final void setElectricScroll(int electricScroll)
+
+
Sets the number of lines from the top and bottom of the text
+ area that are always visible
+
+
+
Parameters:
electricScroll - The number of lines always visible from
+ the top or bottom
+
+
+
+
+
+updateScrollBars
+
+public void updateScrollBars()
+
+
Updates the state of the scroll bars. This should be called
+ if the number of lines in the document changes, or when the
+ size of the text are changes.
+
+
+
+
+
+
+
+
+getFirstLine
+
+public final int getFirstLine()
+
+
Returns the line displayed at the text area's origin.
+
+
+
+
+
+
+
+
+setFirstLine
+
+public void setFirstLine(int firstLine)
+
+
Sets the line displayed at the text area's origin without
+ updating the scroll bars.
+
+
+
+
+
+
+
+
+getVisibleLines
+
+public final int getVisibleLines()
+
+
Returns the number of lines visible in this text area.
+
+
+
+
+
+
+
+
+recalculateVisibleLines
+
+public final void recalculateVisibleLines()
+
+
Recalculates the number of visible lines. This should not
+ be called directly.
+
Sets the horizontal offset of drawn lines. This can be used to
+ implement horizontal scrolling.
+
+
+
Parameters:
horizontalOffset - offset The new horizontal offset
+
+
+
+
+
+setOrigin
+
+public boolean setOrigin(int firstLine,
+ int horizontalOffset)
+
+
A fast way of changing both the first line and horizontal
+ offset.
+
+
+
Parameters:
firstLine - The new first line
horizontalOffset - The new horizontal offset
+
Returns:
True if any of the values were changed, false otherwise
+
+
+
+
+
+scrollToCaret
+
+public boolean scrollToCaret()
+
+
Ensures that the caret is visible by scrolling the text area if
+ necessary.
+
+
+
+
Returns:
True if scrolling was actually performed, false if the
+ caret was already visible
+
+
+
+
+
+scrollTo
+
+public boolean scrollTo(int line,
+ int offset)
+
+
Ensures that the specified line and offset is visible by scrolling
+ the text area if necessary.
+
+
+
Parameters:
line - The line to scroll to
offset - The offset in the line to scroll to
+
Returns:
True if scrolling was actually performed, false if the
+ line and offset was already visible
+
+
+
+
+
+lineToY
+
+public int lineToY(int line)
+
+
Converts a line index to a y co-ordinate.
+
+
+
Parameters:
line - The line
+
+
+
+
+
+yToLine
+
+public int yToLine(int y)
+
+
Converts a y co-ordinate to a line index.
+
+
+
Parameters:
y - The y co-ordinate
+
+
+
+
+
+offsetToX
+
+public final int offsetToX(int line,
+ int offset)
+
+
Converts an offset in a line into an x co-ordinate. This is a
+ slow version that can be used any time.
+
+
+
Parameters:
line - The line
offset - The offset, from the start of the line
+
+
+
+
+
+_offsetToX
+
+public int _offsetToX(int line,
+ int offset)
+
+
Converts an offset in a line into an x co-ordinate. This is a
+ fast version that should only be used if no changes were made
+ to the text since the last repaint.
+
+
+
Parameters:
line - The line
offset - The offset, from the start of the line
+
+
+
+
+
+xToOffset
+
+public int xToOffset(int line,
+ int x)
+
+
Converts an x co-ordinate to an offset within a line.
+
+
+
Parameters:
line - The line
x - The x co-ordinate
+
+
+
+
+
+xyToOffset
+
+public int xyToOffset(int x,
+ int y)
+
+
Converts a point to an offset, from the start of the text.
+
Returns the caret position. This will either be the selection
+ start or the selection end, depending on which direction the
+ selection was made in.
+
+
+
+
+
+
+
+
+getCaretLine
+
+public final int getCaretLine()
+
+
Returns the caret line.
+
+
+
+
+
+
+
+
+getMarkPosition
+
+public final int getMarkPosition()
+
+
Returns the mark position. This will be the opposite selection
+ bound to the caret position.
+
Selects from the start offset to the end offset. This is the
+ general selection method used by all other selecting methods.
+ The caret position will be start if start < end, and end
+ if end > start.
+
+
+
Parameters:
start - The start offset
end - The end offset
+
+
+
+
+
+getSelectedText
+
+public final java.lang.String getSelectedText()
+
+
Returns the selected text, or null if no selection is active.
+
+A KeywordMap is similar to a hashtable in that it maps keys
+ to values. However, the `keys' are Swing segments. This allows lookups of
+ text substrings without the overhead of creating a new string object.
+
+ This class is used by CTokenMarker to map keywords to ids.
+
+
+
+
+
+
+
+
+
+
+
+
+
+Constructor Summary
+
+
+
KeywordMap(boolean ignoreCase)
+
+
+ Creates a new KeywordMap.
+
+
+
KeywordMap(boolean ignoreCase,
+ int mapLength)
+
+
+ Creates a new KeywordMap.
Returns the token marker that is to be used to split lines
+ of this document up into tokens. May return null if this
+ document is not to be colorized.
+
Sets the token marker that is to be used to split lines of
+ this document up into tokens. May throw an exception if
+ this is not supported for this type of document.
+
+
+
Parameters:
tm - The new token marker
+
+
+
+
+
+tokenizeLines
+
+public void tokenizeLines()
+
+
Reparses the document, by passing all lines to the token
+ marker. This should be called after the document is first
+ loaded.
+
+
+
+
+
+
+
+
+tokenizeLines
+
+public void tokenizeLines(int start,
+ int len)
+
+
Reparses the document, by passing the specified lines to the
+ token marker. This should be called after a large quantity of
+ text is first inserted.
+
+
+
Parameters:
start - The first line to parse
len - The number of lines, after the first one to parse
+
+
+
+
+
+beginCompoundEdit
+
+public void beginCompoundEdit()
+
+
Starts a compound edit that can be undone in one operation.
+ Subclasses that implement undo should override this method;
+ this class has no undo functionality so this method is
+ empty.
+
+
+
+
+
+
+
+
+endCompoundEdit
+
+public void endCompoundEdit()
+
+
Ends a compound edit that can be undone in one operation.
+ Subclasses that implement undo should override this method;
+ this class has no undo functionality so this method is
+ empty.
+
+A simple text style class. It can specify the color, italic flag,
+ and bold flag of a run of text.
+
+
+
+
+
+
+
+
+
+
+
+
+
+Constructor Summary
+
+
+
SyntaxStyle(java.awt.Color color,
+ boolean italic,
+ boolean bold)
+
+
+ Creates a new SyntaxStyle.
+
+
+
+
+
+
+
+
+
+Method Summary
+
+
+
+ java.awt.Color
+
getColor()
+
+
+ Returns the color specified in this style.
+
+
+
+ java.awt.FontMetrics
+
getFontMetrics(java.awt.Font font,
+ javax.swing.JComponent comp)
+
+
+ Returns the font metrics for the styled font.
+
+
+
+ java.awt.Font
+
getStyledFont(java.awt.Font font)
+
+
+ Returns the specified font, but with the style's bold and
+ italic flags applied.
+
+
+
+ boolean
+
isBold()
+
+
+ Returns true if boldface is enabled for this style.
+
+
+
+ boolean
+
isItalic()
+
+
+ Returns true if italics is enabled for this style.
+
+
+
+ boolean
+
isPlain()
+
+
+ Returns true if no font styles are enabled.
+
+
+
+ void
+
setGraphicsFlags(java.awt.Graphics gfx,
+ java.awt.Font font)
+
+
+ Sets the foreground color and font of the specified graphics
+ context to that specified in this style.
+
+
+
+ java.lang.String
+
toString()
+
+
+ Returns a string representation of this object.
paintSyntaxLine(javax.swing.text.Segment line,
+ Token tokens,
+ SyntaxStyle[] styles,
+ javax.swing.text.TabExpander expander,
+ java.awt.Graphics gfx,
+ int x,
+ int y)
+
+
+ Paints the specified line onto the graphics context.
+
+
+
+static boolean
+
regionMatches(boolean ignoreCase,
+ javax.swing.text.Segment text,
+ int offset,
+ char[] match)
+
+
+ Checks if a subregion of a Segment is equal to a
+ character array.
+
+
+
+static boolean
+
regionMatches(boolean ignoreCase,
+ javax.swing.text.Segment text,
+ int offset,
+ java.lang.String match)
+
+
+ Checks if a subregion of a Segment is equal to a
+ string.
+Encapsulates default settings for a text area. This can be passed
+ to the constructor once the necessary fields have been filled out.
+ The advantage of doing this over calling lots of set() methods after
+ creating the text area is that this method is faster.
+
Returns the tool tip to display at the specified
+ location. If this highlighter doesn't know what to
+ display, it should delegate to the next highlight
+ painter.
+
+public final void setCaretColor(java.awt.Color caretColor)
+
+
Sets the caret color.
+
+
+
+
+
+
Parameters:
caretColor - The caret color
+
+
+
+
+
+getSelectionColor
+
+public final java.awt.Color getSelectionColor()
+
+
Returns the selection color.
+
+
+
+
+
+
+
+
+
+
+
+setSelectionColor
+
+public final void setSelectionColor(java.awt.Color selectionColor)
+
+
Sets the selection color.
+
+
+
+
+
+
Parameters:
selectionColor - The selection color
+
+
+
+
+
+getLineHighlightColor
+
+public final java.awt.Color getLineHighlightColor()
+
+
Returns the line highlight color.
+
+
+
+
+
+
+
+
+
+
+
+setLineHighlightColor
+
+public final void setLineHighlightColor(java.awt.Color lineHighlightColor)
+
+
Sets the line highlight color.
+
+
+
+
+
+
Parameters:
lineHighlightColor - The line highlight color
+
+
+
+
+
+isLineHighlightEnabled
+
+public final boolean isLineHighlightEnabled()
+
+
Returns true if line highlight is enabled, false otherwise.
+
+
+
+
+
+
+
+
+
+
+
+setLineHighlightEnabled
+
+public final void setLineHighlightEnabled(boolean lineHighlight)
+
+
Enables or disables current line highlighting.
+
+
+
+
+
+
Parameters:
lineHighlight - True if current line highlight
+ should be enabled, false otherwise
+
+
+
+
+
+getBracketHighlightColor
+
+public final java.awt.Color getBracketHighlightColor()
+
+
Returns the bracket highlight color.
+
+
+
+
+
+
+
+
+
+
+
+setBracketHighlightColor
+
+public final void setBracketHighlightColor(java.awt.Color bracketHighlightColor)
+
+
Sets the bracket highlight color.
+
+
+
+
+
+
Parameters:
bracketHighlightColor - The bracket highlight color
+
+
+
+
+
+isBracketHighlightEnabled
+
+public final boolean isBracketHighlightEnabled()
+
+
Returns true if bracket highlighting is enabled, false otherwise.
+ When bracket highlighting is enabled, the bracket matching the
+ one before the caret (if any) is highlighted.
+
+
+
+
+
+
+
+
+
+
+
+setBracketHighlightEnabled
+
+public final void setBracketHighlightEnabled(boolean bracketHighlight)
+
+
Enables or disables bracket highlighting.
+ When bracket highlighting is enabled, the bracket matching the
+ one before the caret (if any) is highlighted.
+
+
+
+
+
+
Parameters:
bracketHighlight - True if bracket highlighting should be
+ enabled, false otherwise
+
+
+
+
+
+isBlockCaretEnabled
+
+public final boolean isBlockCaretEnabled()
+
+
Returns true if the caret should be drawn as a block, false otherwise.
+
+
+
+
+
+
+
+
+
+
+
+setBlockCaretEnabled
+
+public final void setBlockCaretEnabled(boolean blockCaret)
+
+
Sets if the caret should be drawn as a block, false otherwise.
+
+
+
+
+
+
Parameters:
blockCaret - True if the caret should be drawn as a block,
+ false otherwise.
+
+
+
+
+
+getEOLMarkerColor
+
+public final java.awt.Color getEOLMarkerColor()
+
+
Returns the EOL marker color.
+
+
+
+
+
+
+
+
+
+
+
+setEOLMarkerColor
+
+public final void setEOLMarkerColor(java.awt.Color eolMarkerColor)
+
+
Sets the EOL marker color.
+
+
+
+
+
+
Parameters:
eolMarkerColor - The EOL marker color
+
+
+
+
+
+getEOLMarkersPainted
+
+public final boolean getEOLMarkersPainted()
+
+
Returns true if EOL markers are drawn, false otherwise.
+
+
+
+
+
+
+
+
+
+
+
+setEOLMarkersPainted
+
+public final void setEOLMarkersPainted(boolean eolMarkers)
+
+
Sets if EOL markers are to be drawn.
+
+
+
+
+
+
Parameters:
eolMarkers - True if EOL markers should be drawn, false otherwise
+
+
+
+
+
+getInvalidLinesPainted
+
+public boolean getInvalidLinesPainted()
+
+
Returns true if invalid lines are painted as red tildes (~),
+ false otherwise.
+
findMatchingBracket(javax.swing.text.Document doc,
+ int offset)
+
+
+ Returns the offset of the bracket matching the one at the
+ specified offset of the document, or -1 if the bracket is
+ unmatched (or if the character is not a bracket).
+
+
+
+static int
+
findWordEnd(java.lang.String line,
+ int pos,
+ java.lang.String noWordSep)
+
+
+ Locates the end of the word at the specified position.
+
+
+
+static int
+
findWordStart(java.lang.String line,
+ int pos,
+ java.lang.String noWordSep)
+
+
+ Locates the start of the word at the specified position.
+public static int findMatchingBracket(javax.swing.text.Document doc,
+ int offset)
+ throws javax.swing.text.BadLocationException
+
+
Returns the offset of the bracket matching the one at the
+ specified offset of the document, or -1 if the bracket is
+ unmatched (or if the character is not a bracket).
+
+
+
Parameters:
doc - The document
offset - The offset
+
Throws:
+
javax.swing.text.BadLocationException - If an out-of-bounds access
+ was attempted on the document text
+
+
+
+
+
+findWordStart
+
+public static int findWordStart(java.lang.String line,
+ int pos,
+ java.lang.String noWordSep)
+
+
Locates the start of the word at the specified position.
+
+
+
Parameters:
line - The text
pos - The position
+
+
+
+
+
+findWordEnd
+
+public static int findWordEnd(java.lang.String line,
+ int pos,
+ java.lang.String noWordSep)
+
+
Locates the end of the word at the specified position.
+
+A linked list of tokens. Each token has three fields - a token
+ identifier, which is a byte value that can be looked up in the
+ array returned by SyntaxDocument.getColors()
+ to get a color value, a length value which is the length of the
+ token in the text, and a pointer to the next token in the list.
+
This is for use by the token marker implementations
+ themselves. It can be used to store anything that
+ is an object and that needs to exist on a per-line
+ basis.
+
+
+
+
+
+
+
+
+
+
+
+Constructor Detail
+
+
+
+
+TokenMarker.LineInfo
+
+public TokenMarker.LineInfo()
+
+
Creates a new LineInfo object with token = Token.NULL
+ and obj = null.
+
+A token marker that splits lines of text into tokens. Each token carries
+ a length field and an indentification tag that can be mapped to a color
+ for painting that token.
+
+ For performance reasons, the linked list of tokens is reused after each
+ line is tokenized. Therefore, the return value of markTokens
+ should only be used for immediate painting. Notably, it cannot be
+ cached.
+
+
+
+
+
+
+
+
+
+
+
+
+Nested Class Summary
+
+
+
+ class
+
TokenMarker.LineInfo
+
+
+ Inner class for storing information about tokenized lines.
+
+
+
+
+
+
+
+
+
+Method Summary
+
+
+
+ void
+
deleteLines(int index,
+ int lines)
+
+
+ Informs the token marker that line have been deleted from
+ the document.
+
+
+
+ int
+
getLineCount()
+
+
+ Returns the number of lines in this token marker.
+
+
+
+ void
+
insertLines(int index,
+ int lines)
+
+
+ Informs the token marker that lines have been inserted into
+ the document.
+
+
+
+ boolean
+
isNextLineRequested()
+
+
+ Returns true if the next line should be repainted.
markTokens(javax.swing.text.Segment line,
+ int lineIndex)
+
+
+ A wrapper for the lower-level markTokensImpl method
+ that is called to split a line up into tokens.
+
+
+
+ boolean
+
supportsMultilineTokens()
+
+
+ Returns if the token marker supports tokens that span multiple
+ lines.
+public TokenmarkTokens(javax.swing.text.Segment line,
+ int lineIndex)
+
+
A wrapper for the lower-level markTokensImpl method
+ that is called to split a line up into tokens.
+
+
+
Parameters:
line - The line
lineIndex - The line number
+
+
+
+
+
+supportsMultilineTokens
+
+public boolean supportsMultilineTokens()
+
+
Returns if the token marker supports tokens that span multiple
+ lines. If this is true, the object using this token marker is
+ required to pass all lines in the document to the
+ markTokens() method (in turn).
+
+ The default implementation returns true; it should be overridden
+ to return false on simpler token markers for increased speed.
+
+
+
+
+
+
+
+
+insertLines
+
+public void insertLines(int index,
+ int lines)
+
+
Informs the token marker that lines have been inserted into
+ the document. This inserts a gap in the lineInfo
+ array.
+
+
+
Parameters:
index - The first line number
lines - The number of lines
+
+
+
+
+
+deleteLines
+
+public void deleteLines(int index,
+ int lines)
+
+
Informs the token marker that line have been deleted from
+ the document. This removes the lines in question from the
+ lineInfo array.
+
+
+
Parameters:
index - The first line number
lines - The number of lines
+
+
+
+
+
+getLineCount
+
+public int getLineCount()
+
+
Returns the number of lines in this token marker.
+
+
+
+
+
+
+
+
+isNextLineRequested
+
+public boolean isNextLineRequested()
+
+
Returns true if the next line should be repainted. This
+ will return true after a line has been tokenized that starts
+ a multiline token that continues onto the next line.
+
Mouse has been pressed, and should be considered "down"
+ until mouseReleased() is called. If you must, use
+ int button = mouseEvent.getButton();
+ to figure out which button was clicked. It will be one of:
+ MouseEvent.BUTTON1, MouseEvent.BUTTON2, MouseEvent.BUTTON3
+ Note, however, that this is completely inconsistent across
+ platforms.
+
Mouse has been pressed, and should be considered "down"
+ until mouseReleased() is called. If you must, use
+ int button = mouseEvent.getButton();
+ to figure out which button was clicked. It will be one of:
+ MouseEvent.BUTTON1, MouseEvent.BUTTON2, MouseEvent.BUTTON3
+ Note, however, that this is completely inconsistent across
+ platforms.
+
+ Using the keyboard shortcuts, you can copy/paste the values for the
+ colors and paste them into your program. We didn't do any sort of
+ auto-insert of colorMode() or fill() or stroke() code cuz we couldn't
+ decide on a good way to do this.. your contributions welcome).
+
+ Original code by owd.
+ Revised and updated for revision 0108 by Ben Fry (10 March 2006).
+ This code may later be moved to its own 'Tool' plugin, but is included
+ with release 0108+ while features for the "Tools" menu are in testing.
+
+ Updated for 0122 to simply copy the code directly to the clipboard,
+ rather than opening a new window.
+
+ Updated for 0144 to only format the selected lines.
+
+ Notes from the original source:
+ Discourse.java This is a dirty-mix source.
+ NOTE that: No macs and no keyboard. Unreliable source.
+ Only format processing code using fontMetrics.
+ It works under my windows XP + PentiumIV + Processing 0091.
+
+
+
+
+
+
+
+
+
+
+
+
+
+Constructor Summary
+
+
+
DiscourseFormat(Editor editor)
+
+
+ Creates a new window with the formated (YaBB tags) sketchcode
+ from the actual Processing Tab ready to send to the processing discourse
+ web (copy & paste)
Creates a new window with the formated (YaBB tags) sketchcode
+ from the actual Processing Tab ready to send to the processing discourse
+ web (copy & paste)
+
+
+
+
+
+
+
+
+
+Method Detail
+
+
+
+
+show
+
+public void show()
+
+
Format and render sketch code.
+
+
+
+
+
+
+
+
+appendFormattedLine
+
+public void appendFormattedLine(java.lang.StringBuffer cf,
+ int line)
Returns an array containing the constants of this enum type, in
+the order they're declared. This method may be used to iterate
+over the constants as follows:
+
+for(Registry.REGISTRY_ROOT_KEY c : Registry.REGISTRY_ROOT_KEY.values())
+ System.out.println(c);
+
+
+
+
+
Returns:
an array containing the constants of this enum type, in
+the order they're declared
Returns the enum constant of this type with the specified name.
+The string must match exactly an identifier used to declare an
+enum constant in this type. (Extraneous whitespace characters are
+not permitted.)
+
+
+
Parameters:
name - the name of the enum constant to be returned.
+
Returns:
the enum constant with the specified name
+
Throws:
+
java.lang.IllegalArgumentException - if this enum type has no constant
+with the specified name
Get a particular element based on its SVG ID. When editing SVG by hand,
+ this is the id="" tag on any SVG element. When editing from Illustrator,
+ these IDs can be edited by expanding the layers palette. The names used
+ in the layers palette, both for the layers or the shapes and groups
+ beneath them can be used here.
+
+ // This code grabs "Layer 3" and the shapes beneath it.
+ SVG layer3 = svg.get("Layer 3");
+
+Candy is a minimal SVG import library for Processing.
+ Candy was written by Michael Chang, and later revised and
+ expanded for use as a Processing core library by Ben Fry.
+
+ SVG stands for Scalable Vector Graphics, a portable graphics format. It is
+ a vector format so it allows for infinite resolution and relatively small
+ file sizes. Most modern media software can view SVG files, including Adobe
+ products, Firefox, etc. Illustrator and Inkscape can edit SVG files.
+
+ We have no intention of turning this into a full-featured SVG library.
+ The goal of this project is a basic shape importer that is small enough
+ to be included with applets, meaning that its download size should be
+ in the neighborhood of 25-30k. Because of this size, it is not made part
+ of processing.core, as it's not a feature that will be used by the majority
+ of our audience.
+
+ For more sophisticated import/export, consider the
+ Batik
+ library from the Apache Software Foundation. Future improvements to this
+ library may focus on this properly supporting a specific subset of SVG,
+ for instance the simpler SVG profiles known as
+ SVG Tiny or Basic,
+ although we still would not support the interactivity options.
+
+ This library was specifically tested under SVG files created with Adobe
+ Illustrator. We can't guarantee that it will work for any SVGs created with
+ other software. In the future we would like to improve compatibility with
+ Open Source software such as Inkscape, however initial tests show its
+ base implementation produces more complicated files, and this will require
+ more time.
+
+ An SVG created under Illustrator must be created in one of two ways:
+
+
File → Save for Web (or control-alt-shift-s on a PC). Under
+ settings, make sure the CSS properties is set to "Presentation Attributes".
+
With Illustrator CS2, it is also possible to use "Save As" with "SVG"
+ as the file setting, but the CSS properties should also be set similarly.
+
+ Saving it any other way will most likely break Candy.
+
+
+
+ A minimal example program using Candy:
+ (assuming a working moo.svg is in your data folder)
+
+
+
+ Note that processing.xml needs to be imported as well.
+ This may not be required when running code within the Processing
+ environment, but when exported it may cause a NoClassDefError.
+ This will be fixed in later releases of Processing
+ (Bug 518).
+
+
+
+ August 2008 revisions by fry (Processing 0149)
+
+
Major changes to rework around PShape.
+
Now implementing more of the "transform" attribute.
+
+
+ February 2008 revisions by fry (Processing 0136)
+
+
Added support for quadratic curves in paths (Q, q, T, and t operators)
+
Support for reading SVG font data (though not rendering it yet)
+
+
+ Revisions for "Candy 2" November 2006 by fry
+
+
Switch to the new processing.xml library
+
Several bug fixes for parsing of shape data
+
Support for linear and radial gradients
+
Support for additional types of shapes
+
Added compound shapes (shapes with interior points)
+
Added methods to get shapes from an internal table
+
+
+ Revision 10/31/06 by flux
+
+
Now properly supports Processing 0118
+
Fixed a bunch of things for Casey's students and general buggity.
+
Will now properly draw #FFFFFFFF colors (were being represented as -1)
+
SVGs without tags are now properly caught and loaded
+
Added a method customStyle() for overriding SVG colors/styles
+
Added a method SVGStyle() to go back to using SVG colors/styles
+
+
+ Some SVG objects and features may not yet be supported.
+ Here is a partial list of non-included features
+
+
Rounded rectangles
+
Drop shadow objects
+
Typography
+
Layers added for Candy 2
+
Patterns
+
Embedded images
+
+
+ For those interested, the SVG specification can be found
+ here.
+
+
+
+
+
+
+
+
+
+
+
+
+Field Summary
+
+
+
+
+
+
Fields inherited from interface processing.core.PConstants
remove(java.lang.Object object,
+ java.lang.reflect.Method method)
+
+
+ Removes first object/method pair matched (and only the first,
+ must be called multiple times if object is registered multiple times).
Removes first object/method pair matched (and only the first,
+ must be called multiple times if object is registered multiple times).
+ Does not shrink array afterwards, silently returns if method not found.
+
public static class PApplet.RendererChangeException
extends java.lang.RuntimeException
+
+
+
+Exception thrown when size() is called the first time.
+
+ This is used internally so that setup() is forced to run twice
+ when the renderer is changed. This is the only way for us to handle
+ invoking the new renderer while also in the midst of rendering.
+
+Base class for all sketches that use processing.core.
+
+ Note that you should not use AWT or Swing components inside a Processing
+ applet. The surface is made to automatically update itself, and will cause
+ problems with redraw of components drawn above it. If you'd like to
+ integrate other Java components, see below.
+
+ As of release 0145, Processing uses active mode rendering in all cases.
+ All animation tasks happen on the "Processing Animation Thread". The
+ setup() and draw() methods are handled by that thread, and events (like
+ mouse movement and key presses, which are fired by the event dispatch
+ thread or EDT) are queued to be (safely) handled at the end of draw().
+ For code that needs to run on the EDT, use SwingUtilities.invokeLater().
+ When doing so, be careful to synchronize between that code (since
+ invokeLater() will make your code run from the EDT) and the Processing
+ animation thread. Use of a callback function or the registerXxx() methods
+ in PApplet can help ensure that your code doesn't do something naughty.
+
+ As of release 0136 of Processing, we have discontinued support for versions
+ of Java prior to 1.5. We don't have enough people to support it, and for a
+ project of our size, we should be focusing on the future, rather than
+ working around legacy Java code. In addition, Java 1.5 gives us access to
+ better timing facilities which will improve the steadiness of animation.
+
+ This class extends Applet instead of JApplet because 1) historically,
+ we supported Java 1.1, which does not include Swing (without an
+ additional, sizable, download), and 2) Swing is a bloated piece of crap.
+ A Processing applet is a heavyweight AWT component, and can be used the
+ same as any other AWT component, with or without Swing.
+
+ Similarly, Processing runs in a Frame and not a JFrame. However, there's
+ nothing to prevent you from embedding a PApplet into a JFrame, it's just
+ that the base version uses a regular AWT frame because there's simply
+ no need for swing in that context. If people want to use Swing, they can
+ embed themselves as they wish.
+
+ It is possible to use PApplet, along with core.jar in other projects.
+ In addition to enabling you to use Java 1.5+ features with your sketch,
+ this also allows you to embed a Processing drawing area into another Java
+ application. This means you can use standard GUI controls with a Processing
+ sketch. Because AWT and Swing GUI components cannot be used on top of a
+ PApplet, you can instead embed the PApplet inside another GUI the way you
+ would any other Component.
+
+ It is also possible to resize the Processing window by including
+ frame.setResizable(true) inside your setup() method.
+ Note that the Java method frame.setSize() will not work unless
+ you first set the frame to be resizable.
+
+ Because the default animation thread will run at 60 frames per second,
+ an embedded PApplet can make the parent sluggish. You can use frameRate()
+ to make it update less often, or you can use noLoop() and loop() to disable
+ and then re-enable looping. If you want to only update the sketch
+ intermittently, use noLoop() inside setup(), and redraw() whenever
+ the screen needs to be updated once (or loop() to re-enable the animation
+ thread). The following example embeds a sketch and also uses the noLoop()
+ and redraw() methods. You need not use noLoop() and redraw() when embedding
+ if you want your application to animate continuously.
+
+ public class ExampleFrame extends Frame {
+
+ public ExampleFrame() {
+ super("Embedded PApplet");
+
+ setLayout(new BorderLayout());
+ PApplet embed = new Embedded();
+ add(embed, BorderLayout.CENTER);
+
+ // important to call this whenever embedding a PApplet.
+ // It ensures that the animation thread is started and
+ // that other internal variables are properly set.
+ embed.init();
+ }
+ }
+
+ public class Embedded extends PApplet {
+
+ public void setup() {
+ // original setup code here ...
+ size(400, 400);
+
+ // prevent thread from starving everything else
+ noLoop();
+ }
+
+ public void draw() {
+ // drawing code goes here
+ }
+
+ public void mousePressed() {
+ // do something based on mouse movement
+
+ // update the screen (run draw once)
+ redraw();
+ }
+ }
+
+
+
Processing on multiple displays
+
I was asked about Processing with multiple displays, and for lack of a
+ better place to document it, things will go here.
+
You can address both screens by making a window the width of both,
+ and the height of the maximum of both screens. In this case, do not use
+ present mode, because that's exclusive to one screen. Basically it'll
+ give you a PApplet that spans both screens. If using one half to control
+ and the other half for graphics, you'd just have to put the 'live' stuff
+ on one half of the canvas, the control stuff on the other. This works
+ better in windows because on the mac we can't get rid of the menu bar
+ unless it's running in present mode.
+
For more control, you need to write straight java code that uses p5.
+ You can create two windows, that are shown on two separate screens,
+ that have their own PApplet. this is just one of the tradeoffs of one of
+ the things that we don't support in p5 from within the environment
+ itself (we must draw the line somewhere), because of how messy it would
+ get to start talking about multiple screens. It's also not that tough to
+ do by hand w/ some Java code.
arraycopy(java.lang.Object src,
+ int srcPosition,
+ java.lang.Object dst,
+ int dstPosition,
+ int length)
+
+
+ Deprecated.Use arrayCopy() instead.
+
+
+
+static void
+
arrayCopy(java.lang.Object src,
+ int srcPosition,
+ java.lang.Object dst,
+ int dstPosition,
+ int length)
+
+
+ Calls System.arraycopy(), included here so that we can
+ avoid people needing to learn about the System object
+ before they can just copy an array.
beginRaw(java.lang.String renderer,
+ java.lang.String filename)
+
+
+ Begin recording raw shape data to a renderer of the specified type,
+ using the width and height of the main drawing surface.
+
+
+
+ void
+
beginRecord(PGraphics recorder)
+
+
+ Begin recording (echoing) commands to the specified PGraphics object.
beginRecord(java.lang.String renderer,
+ java.lang.String filename)
+
+
+ Begin recording to a new renderer of the specified type, using the width
+ and height of the main drawing surface.
createFont(java.lang.String name,
+ float size,
+ boolean smooth,
+ char[] charset)
+
+
+ Create a .vlw font on the fly from either a font name that's
+ installed on the system, or from a .ttf or .otf that's inside
+ the data folder of this sketch.
createGraphics(int iwidth,
+ int iheight,
+ java.lang.String irenderer,
+ java.lang.String ipath)
+
+
+ Create an offscreen graphics surface for drawing, in this case
+ for a renderer that writes to a file (such as PDF or DXF).
createImage(int wide,
+ int high,
+ int format)
+
+
+ Preferred method of creating new PImage objects, ensures that a
+ reference to the parent PApplet is included, which makes save() work
+ without needing an absolute path.
createOutput(java.lang.String filename)
+
+
+ Similar to createInput() (formerly openStream), this creates a Java
+ OutputStream for a given filename or path.
delay(int napTime)
+
+
+ The delay() function causes the program to halt for a specified time.
+
+
+
+ void
+
destroy()
+
+
+ Called by the browser or applet viewer to inform this applet
+ that it is being reclaimed and that it should destroy
+ any resources that it has allocated.
+
+
+
+ void
+
die(java.lang.String what)
+
+
+ Function for an applet/application to kill itself and
+ display an error.
+
+
+
+ void
+
die(java.lang.String what,
+ java.lang.Exception e)
+
+
+ Same as above but with an exception.
join(java.lang.String[] str,
+ char separator)
+
+
+ Join an array of Strings together as a single String,
+ separated by the whatever's passed in for the separator.
+
+
+
+static java.lang.String
+
join(java.lang.String[] str,
+ java.lang.String separator)
+
+
+ Join an array of Strings together as a single String,
+ separated by the whatever's passed in for the separator.
+
+
+
+ void
+
keyPressed()
+
+
+ Called each time a single key on the keyboard is pressed.
+
+
+
+ void
+
keyPressed(java.awt.event.KeyEvent e)
+
+
+ Overriding keyXxxxx(KeyEvent e) functions will cause the 'key',
+ 'keyCode', and 'keyEvent' variables to no longer work;
+ key events will no longer be queued until the end of draw();
+ and the keyPressed(), keyReleased() and keyTyped() methods
+ will no longer be called.
loadImage(java.lang.String filename,
+ java.lang.String extension)
+
+
+ Identical to loadImage, but allows you to specify the type of
+ image by its extension.
+
+
+
+ void
+
loadPixels()
+
+
+ Override the g.pixels[] function to set the pixels[] array
+ that's part of the PApplet object.
main(java.lang.String[] args)
+
+
+ main() method for running this class from the command line.
+
+
+
+static float
+
map(float value,
+ float istart,
+ float istop,
+ float ostart,
+ float ostop)
+
+
+ Convenience function to map a variable from one coordinate space
+ to another.
match(java.lang.String what,
+ java.lang.String regexp)
+
+
+ Match a string with a regular expression, and returns the match as an
+ array.
+
+
+
+static java.lang.String[][]
+
matchAll(java.lang.String what,
+ java.lang.String regexp)
+
+
+ Identical to match(), except that it returns an array of all matches in
+ the specified String, rather than just the first.
+
+
+
+static float
+
max(float[] list)
+
+
+ Find the maximum value in an array.
mousePressed()
+
+
+ Mouse has been pressed, and should be considered "down"
+ until mouseReleased() is called.
+
+
+
+ void
+
mousePressed(java.awt.event.MouseEvent e)
+
+
+ If you override this or any function that takes a "MouseEvent e"
+ without calling its super.mouseXxxx() then mouseX, mouseY,
+ mousePressed, and mouseEvent will no longer be set.
+
+
+
+ void
+
mouseReleased()
+
+
+ Mouse button has been released.
nfp(int num,
+ int digits)
+
+
+ number format positive (or plus)
+ Formats a number, always placing a - or + sign
+ in the front when it's negative or positive.
+
+
+
+static java.lang.String[]
+
nfs(float[] num,
+ int left,
+ int right)
+
+
+ Number formatter that takes into account whether the number
+ has a sign (positive, negative, etc) in front of it.
nfs(int num,
+ int digits)
+
+
+ number format signed (or space)
+ Formats a number but leaves a blank space in the front
+ when it's positive so that it can be properly aligned with
+ numbers that have a negative sign in front of them.
+
+
+
+ void
+
noCursor()
+
+
+ Hide the cursor by creating a transparent image
+ and using it as a custom cursor.
parseInt(java.lang.String what)
+
+
+ Parse a String into an int value.
+
+
+
+static int[]
+
parseInt(java.lang.String[] what)
+
+
+ Make an array of int elements from an array of String objects.
+
+
+
+static int[]
+
parseInt(java.lang.String[] what,
+ int missing)
+
+
+ Make an array of int elements from an array of String objects.
+
+
+
+static int
+
parseInt(java.lang.String what,
+ int otherwise)
+
+
+ Parse a String to an int, and provide an alternate value that
+ should be used when the number is invalid.
save(java.lang.String filename)
+
+
+ Intercepts any relative paths to make them absolute (relative
+ to the sketch folder) before passing to save() in PImage.
+
+
+
+static void
+
saveBytes(java.io.File file,
+ byte[] buffer)
+
+
+ Saves bytes to a specific File location specified by the user.
+
+
+
+static void
+
saveBytes(java.io.OutputStream output,
+ byte[] buffer)
+
+
+ Spews a buffer of bytes to an OutputStream.
+
+
+
+ void
+
saveBytes(java.lang.String filename,
+ byte[] buffer)
+
+
+ Saves bytes to a file to inside the sketch folder.
+
+
+
+ java.io.File
+
saveFile(java.lang.String where)
+
+
+ Identical to savePath(), but returns a File object.
+
+
+
+ void
+
saveFrame()
+
+
+ Grab an image of what's currently in the drawing area and save it
+ as a .tif or .tga file.
+
+
+
+ void
+
saveFrame(java.lang.String what)
+
+
+ Save the current frame as a .tif or .tga image.
+
+
+
+ java.lang.String
+
savePath(java.lang.String where)
+
+
+ Returns a path inside the applet folder to save to.
saveStream(java.io.File targetFile,
+ java.lang.String sourceLocation)
+
+
+ Identical to the other saveStream(), but writes to a File
+ object, for greater control over the file location.
+
+
+
+ void
+
saveStream(java.lang.String targetFilename,
+ java.lang.String sourceLocation)
+
+
+ Save the contents of a stream to a file in the sketch folder.
size(int iwidth,
+ int iheight,
+ java.lang.String irenderer,
+ java.lang.String ipath)
+
+
+ Creates a new PGraphics object and sets it to the specified size.
split(java.lang.String what,
+ char delim)
+
+
+ Split a string into pieces along a specific character.
+
+
+
+static java.lang.String[]
+
split(java.lang.String what,
+ java.lang.String delim)
+
+
+ Split a String on a specific delimiter.
+
+
+
+static java.lang.String[]
+
splitTokens(java.lang.String what)
+
+
+ Split the provided String at wherever whitespace occurs.
+
+
+
+static java.lang.String[]
+
splitTokens(java.lang.String what,
+ java.lang.String delim)
+
+
+ Splits a string into pieces, using any of the chars in the
+ String 'delim' as separator characters.
+public static final java.lang.String javaVersionName
+
+
Full name of the Java version (i.e. 1.5.0_11).
+ Prior to 0125, this was only the first three digits.
+
+
+
+
+
+
+
+javaVersion
+
+public static final float javaVersion
+
+
Version of Java that's in use, whether 1.1 or 1.3 or whatever,
+ stored as a float.
+
+ Note that because this is stored as a float, the values may
+ not be exactly 1.3 or 1.4. Instead, make sure you're
+ comparing against 1.3f or 1.4f, which will have the same amount
+ of error (i.e. 1.40000001). This could just be a double, but
+ since Processing only uses floats, it's safer for this to be a float
+ because there's no good way to specify a double with the preproc.
+
+
+
+
+
+
+
+platform
+
+public static int platform
+
+
Current platform in use, one of the
+ PConstants WINDOWS, MACOSX, MACOS9, LINUX or OTHER.
+
+
+
+
+
+
+
+MENU_SHORTCUT
+
+public static final int MENU_SHORTCUT
+
+
Modifier flags for the shortcut key used to trigger menus.
+ (Cmd on Mac OS X, Ctrl on Linux and Windows)
+
The PGraphics renderer associated with this PApplet
+
+
+
+
+
+
+
+frame
+
+public java.awt.Frame frame
+
+
The frame containing this applet (if any)
+
+
+
+
+
+
+
+screen
+
+public java.awt.Dimension screen
+
+
The screen size when the applet was started.
+
+ Access this via screen.width and screen.height. To make an applet
+ run at full screen, use size(screen.width, screen.height).
+
+ If you have multiple displays, this will be the size of the main
+ display. Running full screen across multiple displays isn't
+ particularly supported, and requires more monkeying with the values.
+ This probably can't/won't be fixed until/unless I get a dual head
+ system.
+
+ Note that this won't update if you change the resolution
+ of your screen once the the applet is running.
+
+ This variable is not static, because future releases need to be better
+ at handling multiple displays.
+
Minimum dimensions for the window holding an applet.
+ This varies between platforms, Mac OS X 10.3 can do any height
+ but requires at least 128 pixels width. Windows XP has another
+ set of limitations. And for all I know, Linux probably lets you
+ make windows with negative sizes.
+
true if no size() command has been executed. This is used to wait until
+ a size has been set before placing in the window and showing it.
+
+
+
+
+
+
+
+pixels
+
+public int[] pixels
+
+
Pixel buffer from this applet's PGraphics.
+
+ When used with OpenGL or Java2D, this value will
+ be null until loadPixels() has been called.
+
+
+
+
+
+
+
+width
+
+public int width
+
+
width of this applet's associated PGraphics
+
+
+
+
+
+
+
+height
+
+public int height
+
+
height of this applet's associated PGraphics
+
+
+
+
+
+
+
+mouseX
+
+public int mouseX
+
+
current x position of the mouse
+
+
+
+
+
+
+
+mouseY
+
+public int mouseY
+
+
current y position of the mouse
+
+
+
+
+
+
+
+pmouseX
+
+public int pmouseX
+
+
Previous x/y position of the mouse. This will be a different value
+ when inside a mouse handler (like the mouseMoved() method) versus
+ when inside draw(). Inside draw(), pmouseX is updated once each
+ frame, but inside mousePressed() and friends, it's updated each time
+ an event comes through. Be sure to use only one or the other type of
+ means for tracking pmouseX and pmouseY within your sketch, otherwise
+ you're gonna run into trouble.
+
+
+
+
+
+
+
+pmouseY
+
+public int pmouseY
+
+
Previous x/y position of the mouse. This will be a different value
+ when inside a mouse handler (like the mouseMoved() method) versus
+ when inside draw(). Inside draw(), pmouseX is updated once each
+ frame, but inside mousePressed() and friends, it's updated each time
+ an event comes through. Be sure to use only one or the other type of
+ means for tracking pmouseX and pmouseY within your sketch, otherwise
+ you're gonna run into trouble.
+
+
+
+
+
+
+
+firstMouse
+
+public boolean firstMouse
+
+
Used to set pmouseX/Y to mouseX/Y the first time mouseX/Y are used,
+ otherwise pmouseX/Y are always zero, causing a nasty jump.
+
+ Just using (frameCount == 0) won't work since mouseXxxxx()
+ may not be called until a couple frames into things.
+
+
+
+
+
+
+
+mouseButton
+
+public int mouseButton
+
+
Last mouse button pressed, one of LEFT, CENTER, or RIGHT.
+
+ If running on Mac OS, a ctrl-click will be interpreted as
+ the righthand mouse button (unlike Java, which reports it as
+ the left mouse).
+
+
+
+
+
+
+
+mousePressed
+
+public boolean mousePressed
+
+
+
+
+
+
+
+mouseEvent
+
+public java.awt.event.MouseEvent mouseEvent
+
+
+
+
+
+
+
+key
+
+public char key
+
+
Last key pressed.
+
+ If it's a coded key, i.e. UP/DOWN/CTRL/SHIFT/ALT,
+ this will be set to CODED (0xffff or 65535).
+
+
+
+
+
+
+
+keyCode
+
+public int keyCode
+
+
When "key" is set to CODED, this will contain a Java key code.
+
+ For the arrow keys, keyCode will be one of UP, DOWN, LEFT and RIGHT.
+ Also available are ALT, CONTROL and SHIFT. A full set of constants
+ can be obtained from java.awt.event.KeyEvent, from the VK_XXXX variables.
+
+
+
+
+
+
+
+keyPressed
+
+public boolean keyPressed
+
+
true if the mouse is currently pressed.
+
+
+
+
+
+
+
+keyEvent
+
+public java.awt.event.KeyEvent keyEvent
+
+
the last KeyEvent object passed into a mouse function.
+
+
+
+
+
+
+
+focused
+
+public boolean focused
+
+
Gets set to true/false as the applet gains/loses focus.
+
+
+
+
+
+
+
+online
+
+public boolean online
+
+
true if the applet is online.
+
+ This can be used to test how the applet should behave
+ since online situations are different (no file writing, etc).
+
+
+
+
+
+
+
+frameRate
+
+public float frameRate
+
+
The current value of frames per second.
+
+ The initial value will be 10 fps, and will be updated with each
+ frame thereafter. The value is not instantaneous (since that
+ wouldn't be very useful since it would jump around so much),
+ but is instead averaged (integrated) over several frames.
+ As such, this value won't be valid until after 5-10 frames.
+
+
+
+
+
+
+
+frameCount
+
+public int frameCount
+
+
How many frames have been displayed since the applet started.
+
+ This value is read-only do not attempt to set it,
+ otherwise bad things will happen.
+
+ Inside setup(), frameCount is 0.
+ For the first iteration of draw(), frameCount will equal 1.
+
+
+
+
+
+
+
+finished
+
+public boolean finished
+
+
true if this applet has had it.
+
+
+
+
+
+
+
+ARGS_EDITOR_LOCATION
+
+public static final java.lang.String ARGS_EDITOR_LOCATION
+
+
Position of the upper-lefthand corner of the editor window
+ that launched this applet.
+
+public static final java.lang.String ARGS_EXTERNAL
+
+
Location for where to position the applet window on screen.
+
+ This is used by the editor to when saving the previous applet
+ location, or could be used by other classes to launch at a
+ specific position on-screen.
+
By trial and error, four image loading threads seem to work best when
+ loading images from online. This is consistent with the number of open
+ connections that web browsers will maintain. The variable is made public
+ (however no accessor has been added since it's esoteric) if you really
+ want to have control over the value used. For instance, when loading local
+ files, it might be better to only have a single thread (or two) loading
+ images so that you're disk isn't simply jumping around.
+
+
+
+
+
+
+
+selectedFile
+
+public java.io.File selectedFile
+
+
+
+
+
+
+
+ICON_IMAGE
+
+public static final byte[] ICON_IMAGE
+
+
GIF image of the Processing logo.
+
+
+
+
+
+
+
+
+
+
+
+Constructor Detail
+
+
+
+
+PApplet
+
+public PApplet()
+
+
+
+
+
+
+
+
+
+Method Detail
+
+
+
+
+init
+
+public void init()
+
+
+
Overrides:
init in class java.applet.Applet
+
+
+
+
+
+
+
+
+getSketchWidth
+
+public int getSketchWidth()
+
+
+
+
+
+
+
+
+
+
+
+getSketchHeight
+
+public int getSketchHeight()
+
+
+
+
+
+
+
+
+
+
+
+getSketchRenderer
+
+public java.lang.String getSketchRenderer()
+
+
+
+
+
+
+
+
+
+
+
+start
+
+public void start()
+
+
Called by the browser or applet viewer to inform this applet that it
+ should start its execution. It is called after the init method and
+ each time the applet is revisited in a Web page.
+
+ Called explicitly via the first call to PApplet.paint(), because
+ PAppletGL needs to have a usable screen before getting things rolling.
+
+
+
Overrides:
start in class java.applet.Applet
+
+
+
+
+
+
+
+
+stop
+
+public void stop()
+
+
Called by the browser or applet viewer to inform
+ this applet that it should stop its execution.
+
+ Unfortunately, there are no guarantees from the Java spec
+ when or if stop() will be called (i.e. on browser quit,
+ or when moving between web pages), and it's not always called.
+
+
+
Overrides:
stop in class java.applet.Applet
+
+
+
+
+
+
+
+
+destroy
+
+public void destroy()
+
+
Called by the browser or applet viewer to inform this applet
+ that it is being reclaimed and that it should destroy
+ any resources that it has allocated.
+
+ This also attempts to call PApplet.stop(), in case there
+ was an inadvertent override of the stop() function by a user.
+
+ destroy() supposedly gets called as the applet viewer
+ is shutting down the applet. stop() is called
+ first, and then destroy() to really get rid of things.
+ no guarantees on when they're run (on browser quit, or
+ when moving between pages), though.
+
Starts up and creates a two-dimensional drawing surface,
+ or resizes the current drawing surface.
+
+ This should be the first thing called inside of setup().
+
+ If using Java 1.3 or later, this will default to using
+ PGraphics2, the Java2D-based renderer. If using Java 1.1,
+ or if PGraphics2 is not available, then PGraphics will be used.
+ To set your own renderer, use the other version of the size()
+ method that takes a renderer as its last parameter.
+
+ If called once a renderer has already been set, this will
+ use the previous renderer and simply resize it.
+
+
+
+
+
+
+
+
+
+
+
+size
+
+public void size(int iwidth,
+ int iheight,
+ java.lang.String irenderer)
Creates a new PGraphics object and sets it to the specified size.
+
+ Note that you cannot change the renderer once outside of setup().
+ In most cases, you can call size() to give it a new size,
+ but you need to always ask for the same renderer, otherwise
+ you're gonna run into trouble.
+
+ The size() method should *only* be called from inside the setup() or
+ draw() methods, so that it is properly run on the main animation thread.
+ To change the size of a PApplet externally, use setSize(), which will
+ update the component size, and queue a resize of the renderer as well.
+
+
+
+
+
+
+
+
+
+
+
+createGraphics
+
+public PGraphicscreateGraphics(int iwidth,
+ int iheight,
+ java.lang.String irenderer)
+
+
Create an offscreen PGraphics object for drawing. This can be used
+ for bitmap or vector images drawing or rendering.
+
+
Do not use "new PGraphicsXxxx()", use this method. This method
+ ensures that internal variables are set up properly that tie the
+ new graphics context back to its parent PApplet.
+
The basic way to create bitmap images is to use the saveFrame()
+ function.
+
If you want to create a really large scene and write that,
+ first make sure that you've allocated a lot of memory in the Preferences.
+
If you want to create images that are larger than the screen,
+ you should create your own PGraphics object, draw to that, and use
+ save().
+ For now, it's best to use P3D in this scenario.
+ P2D is currently disabled, and the JAVA2D default will give mixed
+ results. An example of using P3D:
+
+
+ PGraphics big;
+
+ void setup() {
+ big = createGraphics(3000, 3000, P3D);
+
+ big.beginDraw();
+ big.background(128);
+ big.line(20, 1800, 1800, 900);
+ // etc..
+ big.endDraw();
+
+ // make sure the file is written to the sketch folder
+ big.save("big.tif");
+ }
+
+
+
It's important to always wrap drawing to createGraphics() with
+ beginDraw() and endDraw() (beginFrame() and endFrame() prior to
+ revision 0115). The reason is that the renderer needs to know when
+ drawing has stopped, so that it can update itself internally.
+ This also handles calling the defaults() method, for people familiar
+ with that.
+
It's not possible to use createGraphics() with the OPENGL renderer,
+ because it doesn't allow offscreen use.
+
With Processing 0115 and later, it's possible to write images in
+ formats other than the default .tga and .tiff. The exact formats and
+ background information can be found in the developer's reference for
+ PImage.save().
+
Create an offscreen graphics surface for drawing, in this case
+ for a renderer that writes to a file (such as PDF or DXF).
+
+
+
+
+
+
Parameters:
ipath - can be an absolute or relative path
+
+
+
+
+
+createImage
+
+public PImagecreateImage(int wide,
+ int high,
+ int format)
+
+
Preferred method of creating new PImage objects, ensures that a
+ reference to the parent PApplet is included, which makes save() work
+ without needing an absolute path.
+
If you override this or any function that takes a "MouseEvent e"
+ without calling its super.mouseXxxx() then mouseX, mouseY,
+ mousePressed, and mouseEvent will no longer be set.
+
+
+
Specified by:
mousePressed in interface java.awt.event.MouseListener
mouseMoved in interface java.awt.event.MouseMotionListener
+
+
+
+
+
+
+
+
+mousePressed
+
+public void mousePressed()
+
+
Mouse has been pressed, and should be considered "down"
+ until mouseReleased() is called. If you must, use
+ int button = mouseEvent.getButton();
+ to figure out which button was clicked. It will be one of:
+ MouseEvent.BUTTON1, MouseEvent.BUTTON2, MouseEvent.BUTTON3
+ Note, however, that this is completely inconsistent across
+ platforms.
+
+
+
+
+
+
+
+
+
+
+
+mouseReleased
+
+public void mouseReleased()
+
+
Mouse button has been released.
+
+
+
+
+
+
+
+
+
+
+
+mouseClicked
+
+public void mouseClicked()
+
+
When the mouse is clicked, mousePressed() will be called,
+ then mouseReleased(), then mouseClicked(). Note that
+ mousePressed is already false inside of mouseClicked().
+
+
+
+
+
+
+
+
+
+
+
+mouseDragged
+
+public void mouseDragged()
+
+
Mouse button is pressed and the mouse has been dragged.
+
+
+
+
+
+
+
+
+
+
+
+mouseMoved
+
+public void mouseMoved()
+
+
Mouse button is not pressed but the mouse has changed locations.
+
Overriding keyXxxxx(KeyEvent e) functions will cause the 'key',
+ 'keyCode', and 'keyEvent' variables to no longer work;
+ key events will no longer be queued until the end of draw();
+ and the keyPressed(), keyReleased() and keyTyped() methods
+ will no longer be called.
+
+
+
Specified by:
keyPressed in interface java.awt.event.KeyListener
keyReleased in interface java.awt.event.KeyListener
+
+
+
+
+
+
+
+
+keyTyped
+
+public void keyTyped(java.awt.event.KeyEvent e)
+
+
+
Specified by:
keyTyped in interface java.awt.event.KeyListener
+
+
+
+
+
+
+
+
+keyPressed
+
+public void keyPressed()
+
+
Called each time a single key on the keyboard is pressed.
+ Because of how operating systems handle key repeats, holding
+ down a key will cause multiple calls to keyPressed(), because
+ the OS repeat takes over.
+
+ Examples for key handling:
+ (Tested on Windows XP, please notify if different on other
+ platforms, I have a feeling Mac OS and Linux may do otherwise)
+
+ 1. Pressing 'a' on the keyboard:
+ keyPressed with key == 'a' and keyCode == 'A'
+ keyTyped with key == 'a' and keyCode == 0
+ keyReleased with key == 'a' and keyCode == 'A'
+
+ 2. Pressing 'A' on the keyboard:
+ keyPressed with key == 'A' and keyCode == 'A'
+ keyTyped with key == 'A' and keyCode == 0
+ keyReleased with key == 'A' and keyCode == 'A'
+
+ 3. Pressing 'shift', then 'a' on the keyboard (caps lock is off):
+ keyPressed with key == CODED and keyCode == SHIFT
+ keyPressed with key == 'A' and keyCode == 'A'
+ keyTyped with key == 'A' and keyCode == 0
+ keyReleased with key == 'A' and keyCode == 'A'
+ keyReleased with key == CODED and keyCode == SHIFT
+
+ 4. Holding down the 'a' key.
+ The following will happen several times,
+ depending on your machine's "key repeat rate" settings:
+ keyPressed with key == 'a' and keyCode == 'A'
+ keyTyped with key == 'a' and keyCode == 0
+ When you finally let go, you'll get:
+ keyReleased with key == 'a' and keyCode == 'A'
+
+ 5. Pressing and releasing the 'shift' key
+ keyPressed with key == CODED and keyCode == SHIFT
+ keyReleased with key == CODED and keyCode == SHIFT
+ (note there is no keyTyped)
+
+ 6. Pressing the tab key in an applet with Java 1.4 will
+ normally do nothing, but PApplet dynamically shuts
+ this behavior off if Java 1.4 is in use (tested 1.4.2_05 Windows).
+ Java 1.1 (Microsoft VM) passes the TAB key through normally.
+ Not tested on other platforms or for 1.3.
+
+
+
+
+
+
+
+
+
+
+
+
+keyReleased
+
+public void keyReleased()
+
+
See keyPressed().
+
+
+
+
+
+
+
+
+
+
+
+keyTyped
+
+public void keyTyped()
+
+
Only called for "regular" keys like letters,
+ see keyPressed() for full documentation.
+
focusLost in interface java.awt.event.FocusListener
+
+
+
+
+
+
+
+
+millis
+
+public int millis()
+
+
Get the number of milliseconds since the applet started.
+
+ This is a function, rather than a variable, because it may
+ change multiple times per frame.
+
+
+
+
+
+
+
+
+
+
+
+second
+
+public static int second()
+
+
Seconds position of the current time.
+
+
+
+
+
+
+
+
+
+
+
+minute
+
+public static int minute()
+
+
Minutes position of the current time.
+
+
+
+
+
+
+
+
+
+
+
+hour
+
+public static int hour()
+
+
Hour position of the current time in international format (0-23).
+
+ To convert this value to American time:
+
int yankeeHour = (hour() % 12);
+ if (yankeeHour == 0) yankeeHour = 12;
+
+
+
+
+
+
+
+
+
+
+
+day
+
+public static int day()
+
+
Get the current day of the month (1 through 31).
+
+ If you're looking for the day of the week (M-F or whatever)
+ or day of the year (1..365) then use java's Calendar.get()
+
+
+
+
+
+
+
+
+
+
+
+month
+
+public static int month()
+
+
Get the current month in range 1 through 12.
+
+
+
+
+
+
+
+
+
+
+
+year
+
+public static int year()
+
+
Get the current year.
+
+
+
+
+
+
+
+
+
+
+
+delay
+
+public void delay(int napTime)
+
+
The delay() function causes the program to halt for a specified time.
+ Delay times are specified in thousandths of a second. For example,
+ running delay(3000) will stop the program for three seconds and
+ delay(500) will stop the program for a half-second. Remember: the
+ display window is updated only at the end of draw(), so putting more
+ than one delay() inside draw() will simply add them together and the new
+ frame will be drawn when the total delay is over.
+
+ I'm not sure if this is even helpful anymore, as the screen isn't
+ updated before or after the delay, meaning which means it just
+ makes the app lock up temporarily.
+
+
+
+
+
+
+
+
+
+
+
+frameRate
+
+public void frameRate(float newRateTarget)
+
+
Set a target frameRate. This will cause delay() to be called
+ after each frame so that the sketch synchronizes to a particular speed.
+ Note that this only sets the maximum frame rate, it cannot be used to
+ make a slow sketch go faster. Sketches have no default frame rate
+ setting, and will attempt to use maximum processor power to achieve
+ maximum speed.
+
Get a param from the web page, or (eventually)
+ from a properties file.
+
+
+
+
+
+
+
+
+
+
+
+status
+
+public void status(java.lang.String what)
+
+
Show status in the status bar of a web browser, or in the
+ System.out console. Eventually this might show status in the
+ p5 environment itself, rather than relying on the console.
+
Launch a process using a platforms shell. This version uses an array
+ to make it easier to deal with spaces in the individual elements.
+ (This avoids the situation of trying to put single or double quotes
+ around different bits).
+
Same as above but with an exception. Also needs work.
+
+
+
+
+
+
+
+
+
+
+
+exit
+
+public void exit()
+
+
Call to safely exit the sketch when finished. For instance,
+ to render a single frame, save it, and quit.
+
+
+
+
+
+
+
+
+
+
+
+save
+
+public void save(java.lang.String filename)
+
+
Intercepts any relative paths to make them absolute (relative
+ to the sketch folder) before passing to save() in PImage.
+ (Changed in 0100)
+
+
+
+
+
+
+
+
+
+
+
+saveFrame
+
+public void saveFrame()
+
+
Grab an image of what's currently in the drawing area and save it
+ as a .tif or .tga file.
+
+ Best used just before endDraw() at the end of your draw().
+ This can only create .tif or .tga images, so if neither extension
+ is specified it defaults to writing a tiff and adds a .tif suffix.
+
+
+
+
+
+
+
+
+
+
+
+saveFrame
+
+public void saveFrame(java.lang.String what)
+
+
Save the current frame as a .tif or .tga image.
+
+ The String passed in can contain a series of # signs
+ that will be replaced with the screengrab number.
+
+ i.e. saveFrame("blah-####.tif");
+ // saves a numbered tiff image, replacing the
+ // #### signs with zeros and the frame number
Replace the cursor with the specified PImage. The x- and y-
+ coordinate of the center will be the center of the image.
+
+
+
+
+
+
+
+
+
+
+
+cursor
+
+public void cursor(PImage image,
+ int hotspotX,
+ int hotspotY)
+
+
Set a custom cursor to an image with a specific hotspot.
+ Only works with JDK 1.2 and later.
+ Currently seems to be broken on Java 1.4 for Mac OS X
+
+ Based on code contributed by Amit Pitaru, plus additional
+ code to handle Java versions via reflection by Jonathan Feinberg.
+ Reflection removed for release 0128 and later.
+
+
+
+
+
+
+
+
+
+
+
+cursor
+
+public void cursor()
+
+
Show the cursor after noCursor() was called.
+ Notice that the program remembers the last set cursor type
+
+
+
+
+
+
+
+
+
+
+
+noCursor
+
+public void noCursor()
+
+
Hide the cursor by creating a transparent image
+ and using it as a custom cursor.
+
Normalize a value to exist between 0 and 1 (inclusive).
+ Mathematically the opposite of lerp(), figures out what proportion
+ a particular value is relative to start and stop coordinates.
+
Convenience function to map a variable from one coordinate space
+ to another. Equivalent to unlerp() followed by lerp().
+
+
+
+
+
+
+
+
+
+
+
+random
+
+public final float random(float howbig)
+
+
Return a random number in the range [0, howbig).
+
+ The number returned will range from zero up to
+ (but not including) 'howbig'.
+
+
+
+
+
+
+
+
+
+
+
+random
+
+public final float random(float howsmall,
+ float howbig)
+
+
Return a random number in the range [howsmall, howbig).
+
+ The number returned will range from 'howsmall' up to
+ (but not including 'howbig'.
+
+ If howsmall is >= howbig, howsmall will be returned,
+ meaning that random(5, 5) will return 5 (useful)
+ and random(7, 4) will return 7 (not useful.. better idea?)
+
+
+
+
+
+
+
+
+
+
+
+randomSeed
+
+public final void randomSeed(long what)
+
+
+
+
+
+
+
+
+
+
+
+noise
+
+public float noise(float x)
+
+
Computes the Perlin noise function value at point x.
+
+
+
+
+
+
+
+
+
+
+
+noise
+
+public float noise(float x,
+ float y)
+
+
Computes the Perlin noise function value at the point x, y.
+
+
+
+
+
+
+
+
+
+
+
+noise
+
+public float noise(float x,
+ float y,
+ float z)
+
+
Computes the Perlin noise function value at x, y, z.
+
Load an image from the data folder or a local directory.
+ Supports .gif (including transparency), .tga, and .jpg images.
+ In Java 1.3 or later, .png images are
+
+ also supported.
+
+ Generally, loadImage() should only be used during setup, because
+ re-loading images inside draw() is likely to cause a significant
+ delay while memory is allocated and the thread blocks while waiting
+ for the image to load because loading is not asynchronous.
+
+ To load several images asynchronously, see more information in the
+ FAQ about writing your own threaded image loading method.
+
+ As of 0096, returns null if no image of that name is found,
+ rather than an error.
+
+ Release 0115 also provides support for reading TIFF and RLE-encoded
+ Targa (.tga) files written by Processing via save() and saveFrame().
+ Other TIFF and Targa files will probably not load, use a different
+ format (gif, jpg and png are safest bets) when creating images with
+ another application to use with Processing.
+
+ Also in release 0115, more image formats (BMP and others) can
+ be read when using Java 1.4 and later. Because many people still
+ use Java 1.1 and 1.3, these formats are not recommended for
+ work that will be posted on the web. To get a list of possible
+ image formats for use with Java 1.4 and later, use the following:
+ println(javax.imageio.ImageIO.getReaderFormatNames())
+
+ Images are loaded via a byte array that is passed to
+ Toolkit.createImage(). Unfortunately, we cannot use Applet.getImage()
+ because it takes a URL argument, which would be a pain in the a--
+ to make work consistently for online and local sketches.
+ Sometimes this causes problems, resulting in issues like
+ Bug 279
+ and
+ Bug 305.
+ In release 0115, everything was instead run through javax.imageio,
+ but that turned out to be very slow, see
+ Bug 392.
+ As a result, starting with 0116, the following happens:
+
+
TGA and TIFF images are loaded using the internal load methods.
+
JPG, GIF, and PNG images are loaded via loadBytes().
+
If the image still isn't loaded, it's passed to javax.imageio.
+
+ For releases 0116 and later, if you have problems such as those seen
+ in Bugs 279 and 305, use Applet.getImage() instead. You'll be stuck
+ with the limitations of getImage() (the headache of dealing with
+ online/offline use). Set up your own MediaTracker, and pass the resulting
+ java.awt.Image to the PImage constructor that takes an AWT image.
+
Create a .vlw font on the fly from either a font name that's
+ installed on the system, or from a .ttf or .otf that's inside
+ the data folder of this sketch.
+
+ Only works with Java 1.3 or later. Many .otf fonts don't seem
+ to be supported by Java, perhaps because they're CFF based?
+
+ Font names are inconsistent across platforms and Java versions.
+ On Mac OS X, Java 1.3 uses the font menu name of the font,
+ whereas Java 1.4 uses the PostScript name of the font. Java 1.4
+ on OS X will also accept the font menu name as well. On Windows,
+ it appears that only the menu names are used, no matter what
+ Java version is in use. Naming system unknown/untested for 1.5.
+
+ Use 'null' for the charset if you want to use any of the 65,536
+ unicode characters that exist in the font. Note that this can
+ produce an enormous file or may cause an OutOfMemoryError.
+
+
+
+
+
+
+
+
+
+
+
+selectInput
+
+public java.lang.String selectInput()
+
+
Open a platform-specific file chooser dialog to select a file for input.
+
+
+
+
+
+
+
Returns:
full path to the selected file, or null if no selection.
+ This method is useful if you want to use the facilities provided
+ by PApplet to easily open things from the data folder or from a URL,
+ but want an InputStream object so that you can use other Java
+ methods to take more control of how the stream is read.
+
+ If the requested item doesn't exist, null is returned.
+ (Prior to 0096, die() would be called, killing the applet)
+
+ For 0096+, the "data" folder is exported intact with subfolders,
+ and openStream() properly handles subdirectories from the data folder
+
+ If not online, this will also check to see if the user is asking
+ for a file whose name isn't properly capitalized. This helps prevent
+ issues when a sketch is exported to the web, where case sensitivity
+ matters, as opposed to Windows and the Mac OS default where
+ case sensitivity is preserved but ignored.
+
+ It is strongly recommended that libraries use this method to open
+ data files, so that the loading sequence is handled in the same way
+ as functions like loadBytes(), loadImage(), etc.
+
+ The filename passed in can be:
+
+
A URL, for instance openStream("http://processing.org/");
+
A file in the sketch's data folder
+
Another file to be opened locally (when running as an application)
+
Load data from a file and shove it into a String array.
+
+ Exceptions are handled internally, when an error, occurs, an
+ exception is printed to the console and 'null' is returned,
+ but the program continues running. This is a tradeoff between
+ 1) showing the user that there was a problem but 2) not requiring
+ that all i/o code is contained in try/catch blocks, for the sake
+ of new users (or people who are just trying to get things done
+ in a "scripting" fashion. If you want to handle exceptions,
+ use Java methods for I/O.
+
Similar to createInput() (formerly openStream), this creates a Java
+ OutputStream for a given filename or path. The file will be created in
+ the sketch folder, or in the same folder as an exported application.
+
+ If the path does not exist, intermediate folders will be created. If an
+ exception occurs, it will be printed to the console, and null will be
+ returned.
+
+ Future releases may also add support for handling HTTP POST via this
+ method (for better symmetry with createInput), however that's maybe a
+ little too clever (and then we'd have to add the same features to the
+ other file functions like createWriter). Who you callin' bloated?
+
Save the contents of a stream to a file in the sketch folder.
+ This is basically saveBytes(blah, loadBytes()), but done
+ more efficiently (and with less confusing syntax).
+
Identical to the other saveStream(), but writes to a File
+ object, for greater control over the file location.
+ Note that unlike other api methods, this will not automatically
+ compress or uncompress gzip files.
+
Saves bytes to a file to inside the sketch folder.
+ The filename can be a relative path, i.e. "poo/bytefun.txt"
+ would save to a file named "bytefun.txt" to a subfolder
+ called 'poo' inside the sketch folder. If the in-between
+ subfolders don't exist, they'll be created.
+
Prepend the sketch folder path to the filename (or path) that is
+ passed in. External libraries should use this function to save to
+ the sketch folder.
+
+ Note that when running as an applet inside a web browser,
+ the sketchPath will be set to null, because security restrictions
+ prevent applets from accessing that information.
+
+ This will also cause an error if the sketch is not inited properly,
+ meaning that init() was never called on the PApplet when hosted
+ my some other main() or by other code. For proper use of init(),
+ see the examples in the main description text for PApplet.
+
Returns a path inside the applet folder to save to. Like sketchPath(),
+ but creates any in-between folders so that things save properly.
+
+ All saveXxxx() functions use the path to the sketch folder, rather than
+ its data folder. Once exported, the data folder will be found inside the
+ jar file of the exported application or applet. In this case, it's not
+ possible to save data into the jar file, because it will often be running
+ from a server, or marked in-use if running from a local file system.
+ With this in mind, saving to the data path doesn't make sense anyway.
+ If you know you're running locally, and want to save to the data folder,
+ use saveXxxx("data/blah.dat").
+
Return a full path to an item in the data folder.
+
+ In this method, the data path is defined not as the applet's actual
+ data path, but a folder titled "data" in the sketch's working
+ directory. When running inside the PDE, this will be the sketch's
+ "data" folder. However, when exported (as application or applet),
+ sketch's data folder is exported as part of the applications jar file,
+ and it's not possible to read/write from the jar file in a generic way.
+ If you need to read data from the jar file, you should use createInput().
+
Takes a path and creates any in-between folders if they don't
+ already exist. Useful when trying to save to a subfolder that
+ may not actually exist.
+
+
+
+
+
+
+
+
+
+
+
+createPath
+
+public static void createPath(java.io.File file)
+
+
+
+
+
+
+
+
+
+
+
+sort
+
+public static byte[] sort(byte[] what)
+
+
+
+
+
+
+
+
+
+
+
+sort
+
+public static byte[] sort(byte[] what,
+ int count)
+
+
+
+
+
+
+
+
+
+
+
+sort
+
+public static char[] sort(char[] what)
+
+
+
+
+
+
+
+
+
+
+
+sort
+
+public static char[] sort(char[] what,
+ int count)
+
+
+
+
+
+
+
+
+
+
+
+sort
+
+public static int[] sort(int[] what)
+
+
+
+
+
+
+
+
+
+
+
+sort
+
+public static int[] sort(int[] what,
+ int count)
+
+
+
+
+
+
+
+
+
+
+
+sort
+
+public static float[] sort(float[] what)
+
+
+
+
+
+
+
+
+
+
+
+sort
+
+public static float[] sort(float[] what,
+ int count)
Remove whitespace characters from the beginning and ending
+ of a String. Works like String.trim() but includes the
+ unicode nbsp character as well.
+
Split the provided String at wherever whitespace occurs.
+ Multiple whitespace (extra spaces or tabs or whatever)
+ between items will count as a single break.
+
+ The whitespace characters are "\t\n\r\f", which are the defaults
+ for java.util.StringTokenizer, plus the unicode non-breaking space
+ character, which is found commonly on files created by or used
+ in conjunction with Mac OS X (character 160, or 0x00A0 in hex).
+
Splits a string into pieces, using any of the chars in the
+ String 'delim' as separator characters. For instance,
+ in addition to white space, you might want to treat commas
+ as a separator. The delimeter characters won't appear in
+ the returned String array.
+
Split a string into pieces along a specific character.
+ Most commonly used to break up a String along a space or a tab
+ character.
+
+ This operates differently than the others, where the
+ single delimeter is the only breaking point, and consecutive
+ delimeters will produce an empty string (""). This way,
+ one can split on tab characters, but maintain the column
+ alignments (of say an excel file) where there are empty columns.
+
Split a String on a specific delimiter. Unlike Java's String.split()
+ method, this does not parse the delimiter as a regexp because it's more
+ confusing than necessary, and String.split() is always available for
+ those who want regexp.
+
Match a string with a regular expression, and returns the match as an
+ array. The first index is the matching expression, and array elements
+ [1] and higher represent each of the groups (sequences found in parens).
+
+ This uses multiline matching (Pattern.MULTILINE) and dotall mode
+ (Pattern.DOTALL) by default, so that ^ and $ match the beginning and
+ end of any lines found in the source, and the . operator will also
+ pick up newline characters.
+
Identical to match(), except that it returns an array of all matches in
+ the specified String, rather than just the first.
+
+
+
+
+
+
+
+
+
+
+
+parseBoolean
+
+public static final boolean parseBoolean(int what)
+
+
Convert an integer to a boolean. Because of how Java handles upgrading
+ numbers, this will also cover byte and char (as they will upgrade to
+ an int without any sort of explicit cast).
+
The preprocessor will convert boolean(what) to parseBoolean(what).
+
+
+
+
+
+
+
Returns:
false if 0, true if any other number
+
+
+
+
+
+parseBoolean
+
+public static final boolean parseBoolean(java.lang.String what)
+
+
Convert the string "true" or "false" to a boolean.
+
+
+
+
+
+
+
Returns:
true if 'what' is "true" or "TRUE", false otherwise
+
+
+
+
+
+parseBoolean
+
+public static final boolean[] parseBoolean(byte[] what)
+
+
Convert a byte array to a boolean array. Each element will be
+ evaluated identical to the integer case, where a byte equal
+ to zero will return false, and any other value will return true.
+
+
+
+
+
+
+
Returns:
array of boolean elements
+
+
+
+
+
+parseBoolean
+
+public static final boolean[] parseBoolean(int[] what)
+
+
Convert an int array to a boolean array. An int equal
+ to zero will return false, and any other value will return true.
+
+
+
+
+
+
+
Returns:
array of boolean elements
+
+
+
+
+
+parseBoolean
+
+public static final boolean[] parseBoolean(java.lang.String[] what)
+
+
+
+
+
+
+
+
+
+
+
+parseByte
+
+public static final byte parseByte(boolean what)
+
+
+
+
+
+
+
+
+
+
+
+parseByte
+
+public static final byte parseByte(char what)
+
+
+
+
+
+
+
+
+
+
+
+parseByte
+
+public static final byte parseByte(int what)
+
+
+
+
+
+
+
+
+
+
+
+parseByte
+
+public static final byte parseByte(float what)
+
+
+
+
+
+
+
+
+
+
+
+parseByte
+
+public static final byte[] parseByte(boolean[] what)
+
+
+
+
+
+
+
+
+
+
+
+parseByte
+
+public static final byte[] parseByte(char[] what)
+
+
+
+
+
+
+
+
+
+
+
+parseByte
+
+public static final byte[] parseByte(int[] what)
+
+
+
+
+
+
+
+
+
+
+
+parseByte
+
+public static final byte[] parseByte(float[] what)
+
+
+
+
+
+
+
+
+
+
+
+parseChar
+
+public static final char parseChar(byte what)
+
+
+
+
+
+
+
+
+
+
+
+parseChar
+
+public static final char parseChar(int what)
+
+
+
+
+
+
+
+
+
+
+
+parseChar
+
+public static final char[] parseChar(byte[] what)
+
+
+
+
+
+
+
+
+
+
+
+parseChar
+
+public static final char[] parseChar(int[] what)
+
+
+
+
+
+
+
+
+
+
+
+parseInt
+
+public static final int parseInt(boolean what)
+
+
+
+
+
+
+
+
+
+
+
+parseInt
+
+public static final int parseInt(byte what)
+
+
Note that parseInt() will un-sign a signed byte value.
+
+
+
+
+
+
+
+
+
+
+
+parseInt
+
+public static final int parseInt(char what)
+
+
Note that parseInt('5') is unlike String in the sense that it
+ won't return 5, but the ascii value. This is because ((int) someChar)
+ returns the ascii value, and parseInt() is just longhand for the cast.
+
+
+
+
+
+
+
+
+
+
+
+parseInt
+
+public static final int parseInt(float what)
+
+
Same as floor(), or an (int) cast.
+
+
+
+
+
+
+
+
+
+
+
+parseInt
+
+public static final int parseInt(java.lang.String what)
+
+
Parse a String into an int value. Returns 0 if the value is bad.
+
+
+
+
+
+
+
+
+
+
+
+parseInt
+
+public static final int parseInt(java.lang.String what,
+ int otherwise)
+
+
Parse a String to an int, and provide an alternate value that
+ should be used when the number is invalid.
+
+
+
+
+
+
+
+
+
+
+
+parseInt
+
+public static final int[] parseInt(boolean[] what)
Make an array of int elements from an array of String objects.
+ If the String can't be parsed as a number, it will be set to zero.
+
+ String s[] = { "1", "300", "44" };
+ int numbers[] = parseInt(s);
+
+ numbers will contain { 1, 300, 44 }
+
+
+
+
+
+
+
+
+
+
+
+parseInt
+
+public static int[] parseInt(java.lang.String[] what,
+ int missing)
+
+
Make an array of int elements from an array of String objects.
+ If the String can't be parsed as a number, its entry in the
+ array will be set to the value of the "missing" parameter.
+
+ String s[] = { "1", "300", "apple", "44" };
+ int numbers[] = parseInt(s, 9999);
+
+ numbers will contain { 1, 300, 9999, 44 }
+
+
+
+
+
+
+
+
+
+
+
+parseFloat
+
+public static final float parseFloat(int what)
+
+
Convert an int to a float value. Also handles bytes because of
+ Java's rules for upgrading values.
+
+
+
+
+
+
+
+
+
+
+
+parseFloat
+
+public static final float parseFloat(java.lang.String what)
+
+
+
+
+
+
+
+
+
+
+
+parseFloat
+
+public static final float parseFloat(java.lang.String what,
+ float otherwise)
+
+
+
+
+
+
+
+
+
+
+
+parseByte
+
+public static final float[] parseByte(byte[] what)
+
+
+
+
+
+
+
+
+
+
+
+parseFloat
+
+public static final float[] parseFloat(int[] what)
+
+
+
+
+
+
+
+
+
+
+
+parseFloat
+
+public static final float[] parseFloat(java.lang.String[] what)
+
+
+
+
+
+
+
+
+
+
+
+parseFloat
+
+public static final float[] parseFloat(java.lang.String[] what,
+ float missing)
+
+
+
+
+
+
+
+
+
+
+
+str
+
+public static final java.lang.String str(boolean x)
+
+
+
+
+
+
+
+
+
+
+
+str
+
+public static final java.lang.String str(byte x)
+
+
+
+
+
+
+
+
+
+
+
+str
+
+public static final java.lang.String str(char x)
+
+
+
+
+
+
+
+
+
+
+
+str
+
+public static final java.lang.String str(int x)
+
+
+
+
+
+
+
+
+
+
+
+str
+
+public static final java.lang.String str(float x)
+
+
+
+
+
+
+
+
+
+
+
+str
+
+public static final java.lang.String[] str(boolean[] x)
+
+
+
+
+
+
+
+
+
+
+
+str
+
+public static final java.lang.String[] str(byte[] x)
+
+
+
+
+
+
+
+
+
+
+
+str
+
+public static final java.lang.String[] str(char[] x)
+
+
+
+
+
+
+
+
+
+
+
+str
+
+public static final java.lang.String[] str(int[] x)
+
+
+
+
+
+
+
+
+
+
+
+str
+
+public static final java.lang.String[] str(float[] x)
+
+
+
+
+
+
+
+
+
+
+
+nf
+
+public static java.lang.String[] nf(int[] num,
+ int digits)
+
+
+
+
+
+
+
+
+
+
+
+nf
+
+public static java.lang.String nf(int num,
+ int digits)
+
+
+
+
+
+
+
+
+
+
+
+nfc
+
+public static java.lang.String[] nfc(int[] num)
+
+
+
+
+
+
+
+
+
+
+
+nfc
+
+public static java.lang.String nfc(int num)
+
+
+
+
+
+
+
+
+
+
+
+nfs
+
+public static java.lang.String nfs(int num,
+ int digits)
+
+
number format signed (or space)
+ Formats a number but leaves a blank space in the front
+ when it's positive so that it can be properly aligned with
+ numbers that have a negative sign in front of them.
+
+
+
+
+
+
+
+
+
+
+
+nfs
+
+public static java.lang.String[] nfs(int[] num,
+ int digits)
+
+
+
+
+
+
+
+
+
+
+
+nfp
+
+public static java.lang.String nfp(int num,
+ int digits)
+
+
number format positive (or plus)
+ Formats a number, always placing a - or + sign
+ in the front when it's negative or positive.
+
+
+
+
+
+
+
+
+
+
+
+nfp
+
+public static java.lang.String[] nfp(int[] num,
+ int digits)
+
+
+
+
+
+
+
+
+
+
+
+nf
+
+public static java.lang.String[] nf(float[] num,
+ int left,
+ int right)
+
+
+
+
+
+
+
+
+
+
+
+nf
+
+public static java.lang.String nf(float num,
+ int left,
+ int right)
+
+
+
+
+
+
+
+
+
+
+
+nfc
+
+public static java.lang.String[] nfc(float[] num,
+ int right)
+
+
+
+
+
+
+
+
+
+
+
+nfc
+
+public static java.lang.String nfc(float num,
+ int right)
+
+
+
+
+
+
+
+
+
+
+
+nfs
+
+public static java.lang.String[] nfs(float[] num,
+ int left,
+ int right)
+
+
Number formatter that takes into account whether the number
+ has a sign (positive, negative, etc) in front of it.
+
+
+
+
+
+
+
+
+
+
+
+nfs
+
+public static java.lang.String nfs(float num,
+ int left,
+ int right)
+
+
+
+
+
+
+
+
+
+
+
+nfp
+
+public static java.lang.String[] nfp(float[] num,
+ int left,
+ int right)
+
+
+
+
+
+
+
+
+
+
+
+nfp
+
+public static java.lang.String nfp(float num,
+ int left,
+ int right)
+
+
+
+
+
+
+
+
+
+
+
+hex
+
+public static final java.lang.String hex(byte what)
+
+
+
+
+
+
+
+
+
+
+
+hex
+
+public static final java.lang.String hex(char what)
+
+
+
+
+
+
+
+
+
+
+
+hex
+
+public static final java.lang.String hex(int what)
+
+
+
+
+
+
+
+
+
+
+
+hex
+
+public static final java.lang.String hex(int what,
+ int digits)
+
+
+
+
+
+
+
+
+
+
+
+unhex
+
+public static final int unhex(java.lang.String what)
+
+
+
+
+
+
+
+
+
+
+
+binary
+
+public static final java.lang.String binary(byte what)
+
+
Returns a String that contains the binary value of a byte.
+ The returned value will always have 8 digits.
+
+
+
+
+
+
+
+
+
+
+
+binary
+
+public static final java.lang.String binary(char what)
+
+
Returns a String that contains the binary value of a char.
+ The returned value will always have 16 digits because chars
+ are two bytes long.
+
+
+
+
+
+
+
+
+
+
+
+binary
+
+public static final java.lang.String binary(int what)
+
+
Returns a String that contains the binary value of an int.
+ The length depends on the size of the number itself.
+ An int can be up to 32 binary digits, but that seems like
+ overkill for almost any situation, so this function just
+ auto-size. If you want a specific number of digits (like all 32)
+ use binary(int what, int digits) to specify how many digits.
+
+
+
+
+
+
+
+
+
+
+
+binary
+
+public static final java.lang.String binary(int what,
+ int digits)
+
+
Returns a String that contains the binary value of an int.
+ The digits parameter determines how many digits will be used.
+
+
+
+
+
+
+
+
+
+
+
+unbinary
+
+public static final int unbinary(java.lang.String what)
+
+
Unpack a binary String into an int.
+ i.e. unbinary("00001000") would return 8.
+
+
+
+
+
+
+
+
+
+
+
+color
+
+public final int color(int gray)
+
+
+
+
+
+
+
+
+
+
+
+color
+
+public final int color(float fgray)
+
+
+
+
+
+
+
+
+
+
+
+color
+
+public final int color(int gray,
+ int alpha)
+
+
As of 0116 this also takes color(#FF8800, alpha)
+
+
+
+
+
+
+
+
+
+
+
+color
+
+public final int color(float fgray,
+ float falpha)
+
+
+
+
+
+
+
+
+
+
+
+color
+
+public final int color(int x,
+ int y,
+ int z)
+
+
+
+
+
+
+
+
+
+
+
+color
+
+public final int color(float x,
+ float y,
+ float z)
+
+
+
+
+
+
+
+
+
+
+
+color
+
+public final int color(int x,
+ int y,
+ int z,
+ int a)
+
+
+
+
+
+
+
+
+
+
+
+color
+
+public final int color(float x,
+ float y,
+ float z,
+ float a)
+
+
+
+
+
+
+
+
+
+
+
+setupExternalMessages
+
+public void setupExternalMessages()
+
+
Set this sketch to communicate its state back to the PDE.
+
+ This uses the stderr stream to write positions of the window
+ (so that it will be saved by the PDE for the next run) and
+ notify on quit. See more notes in the Worker class.
+
+
+
+
+
+
+
+
+
+
+
+setupFrameResizeListener
+
+public void setupFrameResizeListener()
+
+
Set up a listener that will fire proper component resize events
+ in cases where frame.setResizable(true) is called.
+
+
+
+
+
+
+
+
+
+
+
+main
+
+public static void main(java.lang.String[] args)
+
+
main() method for running this class from the command line.
+
+ The options shown here are not yet finalized and will be
+ changing over the next several releases.
+
+ The simplest way to turn and applet into an application is to
+ add the following code to your program:
+
+ This will properly launch your applet from a double-clickable
+ .jar or from the command line.
+
+ Parameters useful for launching or also used by the PDE:
+
+ --location=x,y upper-lefthand corner of where the applet
+ should appear on screen. if not used,
+ the default is to center on the main screen.
+
+ --present put the applet into full screen presentation
+ mode. requires java 1.4 or later.
+
+ --exclusive use full screen exclusive mode when presenting.
+ disables new windows or interaction with other
+ monitors, this is like a "game" mode.
+
+ --hide-stop use to hide the stop button in situations where
+ you don't want to allow users to exit. also
+ see the FAQ on information for capturing the ESC
+ key when running in presentation mode.
+
+ --stop-color=#xxxxxx color of the 'stop' text used to quit an
+ sketch when it's in present mode.
+
+ --bgcolor=#xxxxxx background color of the window.
+
+ --sketch-path location of where to save files from functions
+ like saveStrings() or saveFrame(). defaults to
+ the folder that the java application was
+ launched from, which means if this isn't set by
+ the pde, everything goes into the same folder
+ as processing.exe.
+
+ --display=n set what display should be used by this applet.
+ displays are numbered starting from 1.
+
+ Parameters used by Processing when running via the PDE
+
+ --external set when the applet is being used by the PDE
+
+ --editor-location=x,y position of the upper-lefthand corner of the
+ editor window, for placement of applet window
+
Begin recording raw shape data to a renderer of the specified type,
+ using the width and height of the main drawing surface.
+
+ If hashmarks (###) are found in the filename, they'll be replaced
+ by the current frame number (frameCount).
+
Begin recording raw shape data to the specified renderer.
+
+ This simply echoes to g.beginRaw(), but since is placed here (rather than
+ generated by preproc.pl) for clarity and so that it doesn't echo the
+ command should beginRecord() be in use.
+
+
+
+
+
+
+
+
+
+
+
+endRaw
+
+public void endRaw()
+
+
Stop recording raw shape data to the specified renderer.
+
+ This simply echoes to g.beginRaw(), but since is placed here (rather than
+ generated by preproc.pl) for clarity and so that it doesn't echo the
+ command should beginRecord() be in use.
+
+
+
+
+
+
+
+
+
+
+
+loadPixels
+
+public void loadPixels()
+
+
Override the g.pixels[] function to set the pixels[] array
+ that's part of the PApplet object. Allows the use of
+ pixels[] in the code, rather than g.pixels[].
+
+
+
+
+
+
+
+
+
+
+
+updatePixels
+
+public void updatePixels()
+
+
+
+
+
+
+
+
+
+
+
+updatePixels
+
+public void updatePixels(int x1,
+ int y1,
+ int x2,
+ int y2)
+ An attempt is made to keep the constants as short/non-verbose
+ as possible. For instance, the constant is TIFF instead of
+ FILE_TYPE_TIFF. We'll do this as long as we can get away with it.
+
MAX_FLOAT
+
+
+ Same as Float.MAX_VALUE, but included for parity with MIN_VALUE,
+ and to avoid teaching static methods on the first day.
+
+
+
+static int
+
MAX_INT
+
+
+ Largest possible (positive) integer value
+
+
+
+static float
+
MIN_FLOAT
+
+
+ Note that Float.MIN_VALUE is the smallest positive value
+ for a floating point number, not actually the minimum (negative) value
+ for a float.
+
+
+
+static int
+
MIN_INT
+
+
+ Smallest possible (negative) integer value
Note that Float.MIN_VALUE is the smallest positive value
+ for a floating point number, not actually the minimum (negative) value
+ for a float. This constant equals 0xFF7FFFFF, the smallest (farthest
+ negative) value a float can have before it hits NaN.
+
textMode(MODEL) is the default, meaning that characters
+ will be affected by transformations like any other shapes.
+
+ Changed value in 0093 to not interfere with LEFT, CENTER, and RIGHT.
+
textMode(SHAPE) draws text using the the glyph outlines of
+ individual characters rather than as textures. If the outlines are
+ not available, then textMode(SHAPE) will be ignored and textMode(MODEL)
+ will be used instead. For this reason, be sure to call textMode()
+ after calling textFont().
+
+ Currently, textMode(SHAPE) is only supported by OPENGL mode.
+ It also requires Java 1.2 or higher (OPENGL requires 1.4 anyway)
+
+Grayscale bitmap font class used by Processing.
+
+ Awful (and by that, I mean awesome) ascii (non)art for how this works:
+
+ |
+ | height is the full used height of the image
+ |
+ | ..XX.. }
+ | ..XX.. }
+ | ...... }
+ | XXXX.. } topExtent (top y is baseline - topExtent)
+ | ..XX.. }
+ | ..XX.. } dotted areas are where the image data
+ | ..XX.. } is actually located for the character
+ +---XXXXXX---- } (it extends to the right and down
+ | for power of two texture sizes)
+ ^^^^ leftExtent (amount to move over before drawing the image
+
+ ^^^^^^^^^^^^^^ setWidth (width displaced by char)
+
Name of the font as seen by Java when it was created.
+ If the font is available, the native version will be used.
+
+
+
+
+
+
+
+psname
+
+public java.lang.String psname
+
+
Postscript name of the font that this bitmap was created from.
+
+
+
+
+
+
+
+size
+
+public int size
+
+
"natural" size of the font (most often 48)
+
+
+
+
+
+
+
+smooth
+
+public boolean smooth
+
+
true if smoothing was enabled for this font, used for native impl
+
+
+
+
+
+
+
+mbox2
+
+public int mbox2
+
+
next power of 2 over the max image size (usually 64)
+
+
+
+
+
+
+
+twidth
+
+public int twidth
+
+
texture width, same as mbox2, but reserved for future use
+
+
+
+
+
+
+
+theight
+
+public int theight
+
+
texture height, same as mbox2, but reserved for future use
+
+
+
+
+
+
+
+value
+
+public int[] value
+
+
+
+
+
+
+
+height
+
+public int[] height
+
+
+
+
+
+
+
+width
+
+public int[] width
+
+
+
+
+
+
+
+setWidth
+
+public int[] setWidth
+
+
+
+
+
+
+
+topExtent
+
+public int[] topExtent
+
+
+
+
+
+
+
+leftExtent
+
+public int[] leftExtent
+
+
+
+
+
+
+
+ascent
+
+public int ascent
+
+
+
+
+
+
+
+descent
+
+public int descent
+
+
+
+
+
+
+
+DEFAULT_CHARSET
+
+public static char[] DEFAULT_CHARSET
+
+
The default Processing character set.
+
+ This is the union of the Mac Roman and Windows ANSI (CP1250)
+ character sets. ISO 8859-1 Latin 1 is Unicode characters 0x80 -> 0xFF,
+ and would seem a good standard, but in practice, most P5 users would
+ rather have characters that they expect from their platform's fonts.
+
+ This is more of an interim solution until a much better
+ font solution can be determined. (i.e. create fonts on
+ the fly from some sort of vector format).
+
+ This is used by the Create Font tool, or whatever anyone else dreams
+ up for messing with fonts themselves.
+
+ It is assumed that the calling class will handle closing
+ the stream when finished.
+
+
+
+
+
+
+
Throws:
+
java.io.IOException
+
+
+
+
+
+index
+
+public int index(char c)
+
+
Get index for the char (convert from unicode to bagel charset).
+
+
+
+
+
+
+
Returns:
index into arrays or -1 if not found
+
+
+
+
+
+kern
+
+public float kern(char a,
+ char b)
+
+
Currently un-implemented for .vlw fonts,
+ but honored for layout in case subclasses use it.
+
+
+
+
+
+
+
+
+
+
+
+ascent
+
+public float ascent()
+
+
Returns the ascent of this font from the baseline.
+ The value is based on a font of size 1.
+
+
+
+
+
+
+
+
+
+
+
+descent
+
+public float descent()
+
+
Returns how far this font descends from the baseline.
+ The value is based on a font size of 1.
+
+
+
+
+
+
+
+
+
+
+
+width
+
+public float width(char c)
+
+
Width of this character for a font of size 1.
+
+
+
+
+
+
+
+
+
+
+
+list
+
+public static java.lang.String[] list()
+
+
Get a list of the fonts installed on the system that can be used
+ by Java. Not all fonts can be used in Java, in fact it's mostly
+ only TrueType fonts. OpenType fonts with CFF data such as Adobe's
+ OpenType fonts seem to have trouble (even though they're sort of
+ TrueType fonts as well, or may have a .ttf extension). Regular
+ PostScript fonts seem to work OK, however.
+
+ Not recommended for use in applets, but this is implemented
+ in PFont because the Java methods to access this information
+ have changed between 1.1 and 1.4, and the 1.4 method is
+ typical of the sort of undergraduate-level over-abstraction
+ that the seems to have made its way into the Java API after 1.1.
+
Starting with Java 1.5, Apple broke the ability to specify most fonts.
+ This has been filed as bug #4769141 at bugreporter.apple.com. More info at
+ Bug 407.
+
+Main graphics and rendering context, as well as the base API implementation.
+
+
Subclassing and initializing PGraphics objects
+ Starting in release 0149, subclasses of PGraphics are handled differently.
+ The constructor for subclasses takes no parameters, instead a series of
+ functions are called by the hosting PApplet to specify its attributes.
+
+
setParent(PApplet) - is called to specify the parent PApplet.
+
setPrimary(boolean) - called with true if this PGraphics will be the
+ primary drawing surface used by the sketch, or false if not.
+
setPath(String) - called when the renderer needs a filename or output
+ path, such as with the PDF or DXF renderers.
+
setSize(int, int) - this is called last, at which point it's safe for
+ the renderer to complete its initialization routine.
+
+ The functions were broken out because of the growing number of parameters
+ such as these that might be used by a renderer, yet with the exception of
+ setSize(), it's not clear which will be necessary. So while the size could
+ be passed in to the constructor instead of a setSize() function, a function
+ would still be needed that would notify the renderer that it was time to
+ finish its initialization. Thus, setSize() simply does both.
+
+
Know your rights: public vs. private methods
+ Methods that are protected are often subclassed by other renderers, however
+ they are not set 'public' because they shouldn't be part of the user-facing
+ public API accessible from PApplet. That is, we don't want sketches calling
+ textModeCheck() or vertexTexture() directly.
+
+
Handling warnings and exceptions
+ Methods that are unavailable generally show a warning, unless their lack of
+ availability will soon cause another exception. For instance, if a method
+ like getMatrix() returns null because it is unavailable, an exception will
+ be thrown stating that the method is unavailable, rather than waiting for
+ the NullPointerException that will occur when the sketch tries to use that
+ method. As of release 0149, warnings will only be shown once, and exceptions
+ have been changed to warnings where possible.
+
+
Using xxxxImpl() for subclassing smoothness
+ The xxxImpl() methods are generally renderer-specific handling for some
+ subset if tasks for a particular function (vague enough for you?) For
+ instance, imageImpl() handles drawing an image whose x/y/w/h and u/v coords
+ have been specified, and screen placement (independent of imageMode) has
+ been determined. There's no point in all renderers implementing the
+ if (imageMode == BLAH) placement/sizing logic, so that's handled
+ by PGraphics, which then calls imageImpl() once all that is figured out.
+
+
His brother PImage
+ PGraphics subclasses PImage so that it can be drawn and manipulated in a
+ similar fashion. As such, many methods are inherited from PGraphics,
+ though many are unavailable: for instance, resize() is not likely to be
+ implemented; the same goes for mask(), depending on the situation.
+
+
What's in PGraphics, what ain't
+ For the benefit of subclasses, as much as possible has been placed inside
+ PGraphics. For instance, bezier interpolation code and implementations of
+ the strokeCap() method (that simply sets the strokeCap variable) are
+ handled here. Features that will vary widely between renderers are located
+ inside the subclasses themselves. For instance, all matrix handling code
+ is per-renderer: Java 2D uses its own AffineTransform, P2D uses a PMatrix2D,
+ and PGraphics3D needs to keep continually update forward and reverse
+ transformations. A proper (future) OpenGL implementation will have all its
+ matrix madness handled by the card. Lighting also falls under this
+ category, however the base material property settings (emissive, specular,
+ et al.) are handled in PGraphics because they use the standard colorMode()
+ logic. Subclasses should override methods like emissiveFromCalc(), which
+ is a point where a valid color has been defined internally, and can be
+ applied in some manner based on the calcXxxx values.
+
+
What's in the PGraphics documentation, what ain't
+ Some things are noted here, some things are not. For public API, always
+ refer to the reference
+ on Processing.org for proper explanations. No attempt has been made to
+ keep the javadoc up to date or complete. It's an enormous task for
+ which we simply do not have the time. That is, it's not something that
+ to be done once—it's a matter of keeping the multiple references
+ synchronized (to say nothing of the translation issues), while targeting
+ them for their separate audiences. Ouch.
+
textureImage
+
+
+ Current image being used as a texture
+
+
+
+ int
+
textureMode
+
+
+ Sets whether texture coordinates passed to
+ vertex() calls will be based on coordinates that are
+ based on the IMAGE or NORMALIZED.
+
+
+
+ float
+
textureU
+
+
+ Current horizontal coordinate for texture, will always
+ be between 0 and 1, even if using textureMode(IMAGE).
+
+
+
+ float
+
textureV
+
+
+ Current vertical coordinate for texture, see above.
arc(float a,
+ float b,
+ float c,
+ float d,
+ float start,
+ float stop)
+
+
+ Identical parameters and placement to ellipse,
+ but draws only an arc of that ellipse.
+
+
+
+ void
+
background(float gray)
+
+
+ Set the background to a grayscale value, based on the
+ current colorMode.
+
+
+
+ void
+
background(float gray,
+ float alpha)
+
+
+ See notes about alpha in background(x, y, z, a).
+
+
+
+ void
+
background(float x,
+ float y,
+ float z)
+
+
+ Set the background to an r, g, b or h, s, b value,
+ based on the current colorMode.
+
+
+
+ void
+
background(float x,
+ float y,
+ float z,
+ float a)
+
+
+ Clear the background with a color that includes an alpha value.
+
+
+
+ void
+
background(int rgb)
+
+
+ Set the background to a gray or ARGB color.
+
+
+
+ void
+
background(int rgb,
+ float alpha)
+
+
+ See notes about alpha in background(x, y, z, a).
+
+
+
+ void
+
background(PImage image)
+
+
+ Takes an RGB or ARGB image and sets it as the background.
scale(float sx,
+ float sy)
+
+
+ Scale in X and Y.
+
+
+
+ void
+
scale(float x,
+ float y,
+ float z)
+
+
+ Scale in X, Y, and Z.
+
+
+
+ float
+
screenX(float x,
+ float y)
+
+
+ Given an x and y coordinate, returns the x position of where
+ that point would be placed on screen, once affected by translate(),
+ scale(), or any other transformations.
+
+
+
+ float
+
screenX(float x,
+ float y,
+ float z)
+
+
+ Maps a three dimensional point to its placement on-screen.
+
+
+
+ float
+
screenY(float x,
+ float y)
+
+
+ Given an x and y coordinate, returns the y position of where
+ that point would be placed on screen, once affected by translate(),
+ scale(), or any other transformations.
+
+
+
+ float
+
screenY(float x,
+ float y,
+ float z)
+
+
+ Maps a three dimensional point to its placement on-screen.
+
+
+
+ float
+
screenZ(float x,
+ float y,
+ float z)
+
+
+ Maps a three dimensional point to its placement on-screen.
+
+
+
+ void
+
setMatrix(PMatrix source)
+
+
+ Set the current transformation matrix to the contents of another.
+
+
+
+ void
+
setMatrix(PMatrix2D source)
+
+
+ Set the current transformation to the contents of the specified source.
+
+
+
+ void
+
setMatrix(PMatrix3D source)
+
+
+ Set the current transformation to the contents of the specified source.
textFont(PFont which,
+ float size)
+
+
+ Useful function to set the font and size at the same time.
+
+
+
+ void
+
textLeading(float leading)
+
+
+ Set the text leading to a specific value.
+
+
+
+ void
+
textMode(int mode)
+
+
+ Sets the text rendering/placement to be either SCREEN (direct
+ to the screen, exact coordinates, only use the font's original size)
+ or MODEL (the default, where text is manipulated by translate() and
+ can have a textSize).
+
+
+
+ void
+
textSize(float size)
+
+
+ Sets the text size, also resets the value for the leading.
+
+
+
+ void
+
texture(PImage image)
+
+
+ Set texture image for current shape.
+
+
+
+ void
+
textureMode(int mode)
+
+
+ Set texture mode to either to use coordinates based on the IMAGE
+ (more intuitive for new users) or NORMALIZED (better for advanced chaps)
Max value for green (or saturation) set by colorMode
+
+
+
+
+
+
+
+colorModeZ
+
+public float colorModeZ
+
+
Max value for blue (or value) set by colorMode
+
+
+
+
+
+
+
+colorModeA
+
+public float colorModeA
+
+
Max value for alpha set by colorMode
+
+
+
+
+
+
+
+tint
+
+public boolean tint
+
+
True if tint() is enabled (read-only).
+
+ Using tint/tintColor seems a better option for naming than
+ tintEnabled/tint because the latter seems ugly, even though
+ g.tint as the actual color seems a little more intuitive,
+ it's just that g.tintEnabled is even more unintuitive.
+ Same goes for fill and stroke, et al.
+
+
+
+
+
+
+
+tintColor
+
+public int tintColor
+
+
tint that was last set (read-only)
+
+
+
+
+
+
+
+fill
+
+public boolean fill
+
+
true if fill() is enabled, (read-only)
+
+
+
+
+
+
+
+fillColor
+
+public int fillColor
+
+
fill that was last set (read-only)
+
+
+
+
+
+
+
+stroke
+
+public boolean stroke
+
+
true if stroke() is enabled, (read-only)
+
+
+
+
+
+
+
+strokeColor
+
+public int strokeColor
+
+
stroke that was last set (read-only)
+
+
+
+
+
+
+
+strokeWeight
+
+public float strokeWeight
+
+
Last value set by strokeWeight() (read-only). This has a default
+ setting, rather than fighting with renderers about whether that
+ renderer supports thick lines.
+
+
+
+
+
+
+
+strokeJoin
+
+public int strokeJoin
+
+
Set by strokeJoin() (read-only). This has a default setting
+ so that strokeJoin() need not be called by defaults,
+ because subclasses may not implement it (i.e. PGraphicsGL)
+
+
+
+
+
+
+
+strokeCap
+
+public int strokeCap
+
+
Set by strokeCap() (read-only). This has a default setting
+ so that strokeCap() need not be called by defaults,
+ because subclasses may not implement it (i.e. PGraphicsGL)
+
Last background color that was set, zero if an image
+
+
+
+
+
+
+
+image
+
+public java.awt.Image image
+
+
Java AWT Image object associated with this renderer. For P2D and P3D,
+ this will be associated with their MemoryImageSource. For PGraphicsJava2D,
+ it will be the offscreen drawing buffer.
+
+
+
+
+
+
+
+bezierDetail
+
+public int bezierDetail
+
+
+
+
+
+
+
+curveTightness
+
+public float curveTightness
+
+
+
+
+
+
+
+edge
+
+public boolean edge
+
+
+
+
+
+
+
+normalX
+
+public float normalX
+
+
Current normal vector.
+
+
+
+
+
+
+
+normalY
+
+public float normalY
+
+
Current normal vector.
+
+
+
+
+
+
+
+normalZ
+
+public float normalZ
+
+
Current normal vector.
+
+
+
+
+
+
+
+textureMode
+
+public int textureMode
+
+
Sets whether texture coordinates passed to
+ vertex() calls will be based on coordinates that are
+ based on the IMAGE or NORMALIZED.
+
+
+
+
+
+
+
+textureU
+
+public float textureU
+
+
Current horizontal coordinate for texture, will always
+ be between 0 and 1, even if using textureMode(IMAGE).
+
+
+
+
+
+
+
+textureV
+
+public float textureV
+
+
Current vertical coordinate for texture, see above.
+
Constructor for the PGraphics object. Use this to ensure that
+ the defaults get set properly. In a subclass, use this(w, h)
+ as the first line of a subclass' constructor to properly set
+ the internal fields and defaults.
+
Set (or unset) this as the main drawing surface. Meaning that it can
+ safely be set to opaque (and given a default gray background), or anything
+ else that goes along with that.
+
+
+
+
+
+
+
+
+
+
+
+setPath
+
+public void setPath(java.lang.String path)
+
+
+
+
+
+
+
+
+
+
+
+setSize
+
+public void setSize(int w,
+ int h)
+
+
The final step in setting up a renderer, set its size of this renderer.
+ This was formerly handled by the constructor, but instead it's been broken
+ out so that setParent/setPrimary/setPath can be handled differently.
+
+ Important that this is ignored by preproc.pl because otherwise it will
+ override setSize() in PApplet/Applet/Component, which will 1) not call
+ super.setSize(), and 2) will cause the renderer to be resized from the
+ event thread (EDT), causing a nasty crash as it collides with the
+ animation thread.
+
+
+
+
+
+
+
+
+
+
+
+dispose
+
+public void dispose()
+
+
Handle any takedown for this graphics context.
+
+ This is called when a sketch is shut down and this renderer was
+ specified using the size() command, or inside endRecord() and
+ endRaw(), in order to shut things off.
+
+
+
+
+
+
+
+
+
+
+
+canDraw
+
+public boolean canDraw()
+
+
Some renderers have requirements re: when they are ready to draw.
+
+
+
+
+
+
+
+
+
+
+
+beginDraw
+
+public void beginDraw()
+
+
Prepares the PGraphics for drawing.
+
+ When creating your own PGraphics, you should call this before
+ drawing anything.
+
+
+
+
+
+
+
+
+
+
+
+endDraw
+
+public void endDraw()
+
+
This will finalize rendering so that it can be shown on-screen.
+
+ When creating your own PGraphics, you should call this when
+ you're finished drawing.
+
+
+
+
+
+
+
+
+
+
+
+flush
+
+public void flush()
+
+
+
+
+
+
+
+
+
+
+
+hint
+
+public void hint(int which)
+
+
Enable a hint option.
+
+ For the most part, hints are temporary api quirks,
+ for which a proper api hasn't been properly worked out.
+ for instance SMOOTH_IMAGES existed because smooth()
+ wasn't yet implemented, but it will soon go away.
+
+ They also exist for obscure features in the graphics
+ engine, like enabling/disabling single pixel lines
+ that ignore the zbuffer, the way they do in alphabot.
+
+ Current hint options:
+
+
DISABLE_DEPTH_TEST -
+ turns off the z-buffer in the P3D or OPENGL renderers.
+
+
+
+
+
+
+
+
+
+
+
+
+beginShape
+
+public void beginShape()
+
+
Start a new shape of type POLYGON
+
+
+
+
+
+
+
+
+
+
+
+beginShape
+
+public void beginShape(int kind)
+
+
Start a new shape.
+
+ Differences between beginShape() and line() and point() methods.
+
+ beginShape() is intended to be more flexible at the expense of being
+ a little more complicated to use. it handles more complicated shapes
+ that can consist of many connected lines (so you get joins) or lines
+ mixed with curves.
+
+ The line() and point() command are for the far more common cases
+ (particularly for our audience) that simply need to draw a line
+ or a point on the screen.
+
+ From the code side of things, line() may or may not call beginShape()
+ to do the drawing. In the beta code, they do, but in the alpha code,
+ they did not. they might be implemented one way or the other depending
+ on tradeoffs of runtime efficiency vs. implementation efficiency &mdash
+ meaning the speed that things run at vs. the speed it takes me to write
+ the code and maintain it. for beta, the latter is most important so
+ that's how things are implemented.
+
+
+
+
+
+
+
+
+
+
+
+edge
+
+public void edge(boolean edge)
+
+
Sets whether the upcoming vertex is part of an edge.
+ Equivalent to glEdgeFlag(), for people familiar with OpenGL.
+
Sets the current normal vector. Only applies with 3D rendering
+ and inside a beginShape/endShape block.
+
+ This is for drawing three dimensional shapes and surfaces,
+ allowing you to specify a vector perpendicular to the surface
+ of the shape, which determines how lighting affects it.
+
+ For the most part, PGraphics3D will attempt to automatically
+ assign normals to shapes, but since that's imperfect,
+ this is a better option when you want more control.
+
+ For people familiar with OpenGL, this function is basically
+ identical to glNormal3f().
+
+
+
+
+
+
+
+
+
+
+
+textureMode
+
+public void textureMode(int mode)
+
+
Set texture mode to either to use coordinates based on the IMAGE
+ (more intuitive for new users) or NORMALIZED (better for advanced chaps)
+
Identical parameters and placement to ellipse,
+ but draws only an arc of that ellipse.
+
+ start and stop are always radians because angleMode() was goofy.
+ ellipseMode() sets the placement.
+
+ also tries to be smart about start < stop.
+
+
+
+
+
+
+
+
+
+
+
+box
+
+public void box(float size)
+
+
+
+
+
+
+
+
+
+
+
+box
+
+public void box(float w,
+ float h,
+ float d)
+
+
+
+
+
+
+
+
+
+
+
+sphereDetail
+
+public void sphereDetail(int res)
+
+
+
+
+
+
+
+
+
+
+
+sphereDetail
+
+public void sphereDetail(int ures,
+ int vres)
+
+
Set the detail level for approximating a sphere. The ures and vres params
+ control the horizontal and vertical resolution.
+
+ Code for sphereDetail() submitted by toxi [031031].
+ Code for enhanced u/v version from davbol [080801].
+
+
+
+
+
+
+
+
+
+
+
+sphere
+
+public void sphere(float r)
+
+
Draw a sphere with radius r centered at coordinate 0, 0, 0.
+
+ Implementation notes:
+
+ cache all the points of the sphere in a static array
+ top and bottom are just a bunch of triangles that land
+ in the center point
+
+ sphere is a series of concentric circles who radii vary
+ along the shape, based on, er.. cos or something
+
+ [toxi 031031] new sphere code. removed all multiplies with
+ radius, as scale() will take care of that anyway
+
+ [toxi 031223] updated sphere code (removed modulos)
+ and introduced sphereAt(x,y,z,r)
+ to avoid additional translate()'s on the user/sketch side
+
+ [davbol 080801] now using separate sphereDetailU/V
+
Evalutes quadratic bezier at point t for points a, b, c, d.
+ t varies between 0 and 1, and a and d are the on curve points,
+ b and c are the control points. this can be done once with the
+ x coordinates and a second time with the y coordinates to get
+ the location of a bezier curve at t.
+
+ For instance, to convert the following example:
+ stroke(255, 102, 0);
+ line(85, 20, 10, 10);
+ line(90, 90, 15, 80);
+ stroke(0, 0, 0);
+ bezier(85, 20, 10, 10, 90, 90, 15, 80);
+
+ // draw it in gray, using 10 steps instead of the default 20
+ // this is a slower way to do it, but useful if you need
+ // to do things with the coordinates at each step
+ stroke(128);
+ beginShape(LINE_STRIP);
+ for (int i = 0; i <= 10; i++) {
+ float t = i / 10.0f;
+ float x = bezierPoint(85, 10, 90, 15, t);
+ float y = bezierPoint(20, 10, 90, 80, t);
+ vertex(x, y);
+ }
+ endShape();
Draw a cubic bezier curve. The first and last points are
+ the on-curve points. The middle two are the 'control' points,
+ or 'handles' in an application like Illustrator.
+
+ As of 0070, this function no longer doubles the first and
+ last points. The curves are a bit more boring, but it's more
+ mathematically correct, and properly mirrored in curvePoint().
+
+public void image(PImage image,
+ float a,
+ float b,
+ float c,
+ float d,
+ int u1,
+ int v1,
+ int u2,
+ int v2)
+
+
Draw an image(), also specifying u/v coordinates.
+ In this method, the u, v coordinates are always based on image space
+ location, regardless of the current textureMode().
+
+
+
+
+
+
+
+
+
+
+
+shapeMode
+
+public void shapeMode(int mode)
+
+
Set the orientation for the shape() command (like imageMode() or rectMode()).
+
Sets the alignment of the text to one of LEFT, CENTER, or RIGHT.
+ This will also reset the vertical text alignment to BASELINE.
+
+
+
+
+
+
+
+
+
+
+
+textAlign
+
+public void textAlign(int alignX,
+ int alignY)
+
+
Sets the horizontal and vertical alignment of the text. The horizontal
+ alignment can be one of LEFT, CENTER, or RIGHT. The vertical alignment
+ can be TOP, BOTTOM, CENTER, or the BASELINE (the default).
+
+
+
+
+
+
+
+
+
+
+
+textAscent
+
+public float textAscent()
+
+
Returns the ascent of the current font at the current size.
+ This is a method, rather than a variable inside the PGraphics object
+ because it requires calculation.
+
+
+
+
+
+
+
+
+
+
+
+textDescent
+
+public float textDescent()
+
+
Returns the descent of the current font at the current size.
+ This is a method, rather than a variable inside the PGraphics object
+ because it requires calculation.
+
Sets the current font. The font's size will be the "natural"
+ size of this font (the size that was set when using "Create Font").
+ The leading will also be reset.
+
Useful function to set the font and size at the same time.
+
+
+
+
+
+
+
+
+
+
+
+textLeading
+
+public void textLeading(float leading)
+
+
Set the text leading to a specific value. If using a custom
+ value for the text leading, you'll have to call textLeading()
+ again after any calls to textSize().
+
+
+
+
+
+
+
+
+
+
+
+textMode
+
+public void textMode(int mode)
+
+
Sets the text rendering/placement to be either SCREEN (direct
+ to the screen, exact coordinates, only use the font's original size)
+ or MODEL (the default, where text is manipulated by translate() and
+ can have a textSize). The text size cannot be set when using
+ textMode(SCREEN), because it uses the pixels directly from the font.
+
+
+
+
+
+
+
+
+
+
+
+textSize
+
+public void textSize(float size)
+
+
Sets the text size, also resets the value for the leading.
+
+
+
+
+
+
+
+
+
+
+
+textWidth
+
+public float textWidth(char c)
+
+
+
+
+
+
+
+
+
+
+
+textWidth
+
+public float textWidth(java.lang.String str)
+
+
Return the width of a line of text. If the text has multiple
+ lines, this returns the length of the longest line.
+
+
+
+
+
+
+
+
+
+
+
+text
+
+public void text(char c)
+
+
Write text where we just left off.
+
+
+
+
+
+
+
+
+
+
+
+text
+
+public void text(char c,
+ float x,
+ float y)
+
+
Draw a single character on screen.
+ Extremely slow when used with textMode(SCREEN) and Java 2D,
+ because loadPixels has to be called first and updatePixels last.
+
Draw a chunk of text.
+ Newlines that are \n (Unix newline or linefeed char, ascii 10)
+ are honored, but \r (carriage return, Windows and Mac OS) are
+ ignored.
+
+
+
+
+
+
+
+
+
+
+
+text
+
+public void text(char[] chars,
+ int start,
+ int stop,
+ float x,
+ float y)
+
+
Method to draw text from an array of chars. This method will usually be
+ more efficient than drawing from a String object, because the String will
+ not be converted to a char array before drawing.
+
Draw text in a box that is constrained to a particular size.
+ The current rectMode() determines what the coordinates mean
+ (whether x1/y1/x2/y2 or x/y/w/h).
+
+ Note that the x,y coords of the start of the box
+ will align with the *ascent* of the text, not the baseline,
+ as is the case for the other text() functions.
+
+ Newlines that are \n (Unix newline or linefeed char, ascii 10)
+ are honored, and \r (carriage return, Windows and Mac OS) are
+ ignored.
+
This does a basic number formatting, to avoid the
+ generally ugly appearance of printing floats.
+ Users who want more control should use their own nf() cmmand,
+ or if they want the long, ugly version of float,
+ use String.valueOf() to convert the float to a String first.
+
Two dimensional rotation.
+
+ Same as rotateZ (this is identical to a 3D rotation along the z-axis)
+ but included for clarity. It'd be weird for people drawing 2D graphics
+ to be using rotateZ. And they might kick our a-- for the confusion.
+
+ Additional background.
+
+
+
+
+
+
+
+
+
+
+
+rotateX
+
+public void rotateX(float angle)
+
+
Rotate around the X axis.
+
+
+
+
+
+
+
+
+
+
+
+rotateY
+
+public void rotateY(float angle)
+
+
Rotate around the Y axis.
+
+
+
+
+
+
+
+
+
+
+
+rotateZ
+
+public void rotateZ(float angle)
+
+
Rotate around the Z axis.
+
+ The functions rotate() and rotateZ() are identical, it's just that it make
+ sense to have rotate() and then rotateX() and rotateY() when using 3D;
+ nor does it make sense to use a function called rotateZ() if you're only
+ doing things in 2D. so we just decided to have them both be the same.
+
Rotate about a vector in space. Same as the glRotatef() function.
+
+
+
+
+
+
+
+
+
+
+
+scale
+
+public void scale(float s)
+
+
Scale in all dimensions.
+
+
+
+
+
+
+
+
+
+
+
+scale
+
+public void scale(float sx,
+ float sy)
+
+
Scale in X and Y. Equivalent to scale(sx, sy, 1).
+
+ Not recommended for use in 3D, because the z-dimension is just
+ scaled by 1, since there's no way to know what else to scale it by.
+
+
+
+
+
+
+
+
+
+
+
+scale
+
+public void scale(float x,
+ float y,
+ float z)
+
+
Scale in X, Y, and Z.
+
+
+
+
+
+
+
+
+
+
+
+resetMatrix
+
+public void resetMatrix()
+
+
Set the current transformation matrix to identity.
+
Given an x and y coordinate, returns the x position of where
+ that point would be placed on screen, once affected by translate(),
+ scale(), or any other transformations.
+
+
+
+
+
+
+
+
+
+
+
+screenY
+
+public float screenY(float x,
+ float y)
+
+
Given an x and y coordinate, returns the y position of where
+ that point would be placed on screen, once affected by translate(),
+ scale(), or any other transformations.
+
+
+
+
+
+
+
+
+
+
+
+screenX
+
+public float screenX(float x,
+ float y,
+ float z)
+
+
Maps a three dimensional point to its placement on-screen.
+
+ Given an (x, y, z) coordinate, returns the x position of where
+ that point would be placed on screen, once affected by translate(),
+ scale(), or any other transformations.
+
+
+
+
+
+
+
+
+
+
+
+screenY
+
+public float screenY(float x,
+ float y,
+ float z)
+
+
Maps a three dimensional point to its placement on-screen.
+
+ Given an (x, y, z) coordinate, returns the y position of where
+ that point would be placed on screen, once affected by translate(),
+ scale(), or any other transformations.
+
+
+
+
+
+
+
+
+
+
+
+screenZ
+
+public float screenZ(float x,
+ float y,
+ float z)
+
+
Maps a three dimensional point to its placement on-screen.
+
+ Given an (x, y, z) coordinate, returns its z value.
+ This value can be used to determine if an (x, y, z) coordinate
+ is in front or in back of another (x, y, z) coordinate.
+ The units are based on how the zbuffer is set up, and don't
+ relate to anything "real". They're only useful for in
+ comparison to another value obtained from screenZ(),
+ or directly out of the zbuffer[].
+
+
+
+
+
+
+
+
+
+
+
+modelX
+
+public float modelX(float x,
+ float y,
+ float z)
+
+
Returns the model space x value for an x, y, z coordinate.
+
+ This will give you a coordinate after it has been transformed
+ by translate(), rotate(), and camera(), but not yet transformed
+ by the projection matrix. For instance, his can be useful for
+ figuring out how points in 3D space relate to the edge
+ coordinates of a shape.
+
+
+
+
+
+
+
+
+
+
+
+modelY
+
+public float modelY(float x,
+ float y,
+ float z)
+
+
Returns the model space y value for an x, y, z coordinate.
+
+
+
+
+
+
+
+
+
+
+
+modelZ
+
+public float modelZ(float x,
+ float y,
+ float z)
+
+
Returns the model space z value for an x, y, z coordinate.
+
+public void lightSpecular(float x,
+ float y,
+ float z)
+
+
+
+
+
+
+
+
+
+
+
+background
+
+public void background(int rgb)
+
+
Set the background to a gray or ARGB color.
+
+ For the main drawing surface, the alpha value will be ignored. However,
+ alpha can be used on PGraphics objects from createGraphics(). This is
+ the only way to set all the pixels partially transparent, for instance.
+
+ Note that background() should be called before any transformations occur,
+ because some implementations may require the current transformation matrix
+ to be identity before drawing.
+
+
+
+
+
+
+
+
+
+
+
+background
+
+public void background(int rgb,
+ float alpha)
+
+
See notes about alpha in background(x, y, z, a).
+
+
+
+
+
+
+
+
+
+
+
+background
+
+public void background(float gray)
+
+
Set the background to a grayscale value, based on the
+ current colorMode.
+
See notes about alpha in background(x, y, z, a).
+
+
+
+
+
+
+
+
+
+
+
+background
+
+public void background(float x,
+ float y,
+ float z)
+
+
Set the background to an r, g, b or h, s, b value,
+ based on the current colorMode.
+
+
+
+
+
+
+
+
+
+
+
+background
+
+public void background(float x,
+ float y,
+ float z,
+ float a)
+
+
Clear the background with a color that includes an alpha value. This can
+ only be used with objects created by createGraphics(), because the main
+ drawing surface cannot be set transparent.
+
+ It might be tempting to use this function to partially clear the screen
+ on each frame, however that's not how this function works. When calling
+ background(), the pixels will be replaced with pixels that have that level
+ of transparency. To do a semi-transparent overlay, use fill() with alpha
+ and draw a rectangle.
+
Takes an RGB or ARGB image and sets it as the background.
+ The width and height of the image must be the same size as the sketch.
+ Use image.resize(width, height) to make short work of such a task.
+
+ Note that even if the image is set as RGB, the high 8 bits of each pixel
+ should be set opaque (0xFF000000), because the image data will be copied
+ directly to the screen, and non-opaque background images may have strange
+ behavior. Using image.filter(OPAQUE) will handle this easily.
+
+ When using 3D, this will also clear the zbuffer (if it exists).
+
+
+
+
+
+
+
+
+
+
+
+colorMode
+
+public void colorMode(int mode)
+
+
Callback to handle clearing the background when begin/endRaw is in use.
+ Handled as separate function for OpenGL (or other) subclasses that
+ override backgroundImpl() but still needs this to work properly.
+
Show an renderer-related exception that halts the program. Currently just
+ wraps the message as a RuntimeException and throws it, but might do
+ something more specific might be used in the future.
+
+
+
+
+
+
+
+
+
+
+
+displayable
+
+public boolean displayable()
+
+
Return true if this renderer should be drawn to the screen. Defaults to
+ returning true, since nearly all renderers are on-screen beasts. But can
+ be overridden for subclasses like PDF so that a window doesn't open up.
+
+ A better name? showFrame, displayable, isVisible, visible, shouldDisplay,
+ what to call this?
+
+
+
+
+
+
+
+
+
+
+
+is2D
+
+public boolean is2D()
+
+
Return true if this renderer supports 2D drawing. Defaults to true.
+
+
+
+
+
+
+
+
+
+
+
+is3D
+
+public boolean is3D()
+
+
Return true if this renderer supports 2D drawing. Defaults to true.
+
+Subclass of PGraphics that handles fast 2D rendering using a
+ MemoryImageSource. The renderer found in this class is not as accurate as
+ PGraphicsJava2D, but offers certain speed tradeoffs, particular when
+ messing with the pixels array, or displaying image or video data.
+
+
+
+
+
+
+
+
+
+
+
+
+Field Summary
+
+
+
+
+
+
Fields inherited from class processing.core.PGraphics
scale(float sx,
+ float sy)
+
+
+ Scale in X and Y.
+
+
+
+ void
+
scale(float x,
+ float y,
+ float z)
+
+
+ Scale in X, Y, and Z.
+
+
+
+ float
+
screenX(float x,
+ float y)
+
+
+ Given an x and y coordinate, returns the x position of where
+ that point would be placed on screen, once affected by translate(),
+ scale(), or any other transformations.
+
+
+
+ float
+
screenY(float x,
+ float y)
+
+
+ Given an x and y coordinate, returns the y position of where
+ that point would be placed on screen, once affected by translate(),
+ scale(), or any other transformations.
+
+
+
+ void
+
sphere(float r)
+
+
+ Draw a sphere with radius r centered at coordinate 0, 0, 0.
This will finalize rendering so that it can be shown on-screen.
+
+ When creating your own PGraphics, you should call this when
+ you're finished drawing.
+
+ Differences between beginShape() and line() and point() methods.
+
+ beginShape() is intended to be more flexible at the expense of being
+ a little more complicated to use. it handles more complicated shapes
+ that can consist of many connected lines (so you get joins) or lines
+ mixed with curves.
+
+ The line() and point() command are for the far more common cases
+ (particularly for our audience) that simply need to draw a line
+ or a point on the screen.
+
+ From the code side of things, line() may or may not call beginShape()
+ to do the drawing. In the beta code, they do, but in the alpha code,
+ they did not. they might be implemented one way or the other depending
+ on tradeoffs of runtime efficiency vs. implementation efficiency &mdash
+ meaning the speed that things run at vs. the speed it takes me to write
+ the code and maintain it. for beta, the latter is most important so
+ that's how things are implemented.
+
Set the detail level for approximating a sphere. The ures and vres params
+ control the horizontal and vertical resolution.
+
+ Code for sphereDetail() submitted by toxi [031031].
+ Code for enhanced u/v version from davbol [080801].
+
Draw a sphere with radius r centered at coordinate 0, 0, 0.
+
+ Implementation notes:
+
+ cache all the points of the sphere in a static array
+ top and bottom are just a bunch of triangles that land
+ in the center point
+
+ sphere is a series of concentric circles who radii vary
+ along the shape, based on, er.. cos or something
+
+ [toxi 031031] new sphere code. removed all multiplies with
+ radius, as scale() will take care of that anyway
+
+ [toxi 031223] updated sphere code (removed modulos)
+ and introduced sphereAt(x,y,z,r)
+ to avoid additional translate()'s on the user/sketch side
+
+ [davbol 080801] now using separate sphereDetailU/V
+
Two dimensional rotation.
+
+ Same as rotateZ (this is identical to a 3D rotation along the z-axis)
+ but included for clarity. It'd be weird for people drawing 2D graphics
+ to be using rotateZ. And they might kick our a-- for the confusion.
+
+ Additional background.
+
Rotate around the Z axis.
+
+ The functions rotate() and rotateZ() are identical, it's just that it make
+ sense to have rotate() and then rotateX() and rotateY() when using 3D;
+ nor does it make sense to use a function called rotateZ() if you're only
+ doing things in 2D. so we just decided to have them both be the same.
+
Scale in X and Y. Equivalent to scale(sx, sy, 1).
+
+ Not recommended for use in 3D, because the z-dimension is just
+ scaled by 1, since there's no way to know what else to scale it by.
+
Given an x and y coordinate, returns the x position of where
+ that point would be placed on screen, once affected by translate(),
+ scale(), or any other transformations.
+
Given an x and y coordinate, returns the y position of where
+ that point would be placed on screen, once affected by translate(),
+ scale(), or any other transformations.
+
+Subclass of PGraphics that handles 3D rendering.
+ It can render 3D inside a browser window and requires no plug-ins.
+
+ The renderer is mostly set up based on the structure of the OpenGL API,
+ if you have questions about specifics that aren't covered here,
+ look for reference on the OpenGL implementation of a similar feature.
+
+ Lighting and camera implementation by Simon Greenwold.
+
flush()
+
+
+ Emit any sorted geometry that's been collected on this frame.
+
+
+
+ void
+
frustum(float left,
+ float right,
+ float bottom,
+ float top,
+ float znear,
+ float zfar)
+
+
+ Same as glFrustum(), except that it wipes out (rather than
+ multiplies against) the current perspective matrix.
ortho()
+
+
+ Calls ortho() with the proper parameters for Processing's
+ standard orthographic projection.
+
+
+
+ void
+
ortho(float left,
+ float right,
+ float bottom,
+ float top,
+ float near,
+ float far)
+
+
+ Similar to gluOrtho(), but wipes out the current projection matrix.
+
+
+
+ void
+
perspective()
+
+
+ Calls perspective() with Processing's standard coordinate projection.
+
+
+
+ void
+
perspective(float fov,
+ float aspect,
+ float zNear,
+ float zFar)
+
+
+ Similar to gluPerspective().
popMatrix()
+
+
+ Replace the current transformation matrix with the top of the stack.
+
+
+
+ void
+
printCamera()
+
+
+ Print the current camera matrix.
+
+
+
+ void
+
printMatrix()
+
+
+ Print the current model (or "transformation") matrix.
+
+
+
+ void
+
printProjection()
+
+
+ Print the current projection matrix.
+
+
+
+ void
+
pushMatrix()
+
+
+ Push a copy of the current transformation matrix onto the stack.
+
+
+
+ void
+
resetMatrix()
+
+
+ Set the current transformation matrix to identity.
+
+
+
+ void
+
rotate(float angle)
+
+
+ Two dimensional rotation.
+
+
+
+ void
+
rotate(float angle,
+ float v0,
+ float v1,
+ float v2)
+
+
+ Rotate around an arbitrary vector, similar to glRotate(),
+ except that it takes radians (instead of degrees).
+
+
+
+ void
+
rotateX(float angle)
+
+
+ Rotate around the X axis.
+
+
+
+ void
+
rotateY(float angle)
+
+
+ Rotate around the Y axis.
+
+
+
+ void
+
rotateZ(float angle)
+
+
+ Rotate around the Z axis.
scale(float sx,
+ float sy)
+
+
+ Same as scale(sx, sy, 1).
+
+
+
+ void
+
scale(float x,
+ float y,
+ float z)
+
+
+ Scale in three dimensions.
+
+
+
+ float
+
screenX(float x,
+ float y)
+
+
+ Given an x and y coordinate, returns the x position of where
+ that point would be placed on screen, once affected by translate(),
+ scale(), or any other transformations.
+
+
+
+ float
+
screenX(float x,
+ float y,
+ float z)
+
+
+ Maps a three dimensional point to its placement on-screen.
+
+
+
+ float
+
screenY(float x,
+ float y)
+
+
+ Given an x and y coordinate, returns the y position of where
+ that point would be placed on screen, once affected by translate(),
+ scale(), or any other transformations.
+
+
+
+ float
+
screenY(float x,
+ float y,
+ float z)
+
+
+ Maps a three dimensional point to its placement on-screen.
+
+
+
+ float
+
screenZ(float x,
+ float y,
+ float z)
+
+
+ Maps a three dimensional point to its placement on-screen.
+
+
+
+ void
+
setMatrix(PMatrix2D source)
+
+
+ Set the current transformation to the contents of the specified source.
+
+
+
+ void
+
setMatrix(PMatrix3D source)
+
+
+ Set the current transformation to the contents of the specified source.
+
+
+
+ void
+
setSize(int iwidth,
+ int iheight)
+
+
+ Called in response to a resize event, handles setting the
+ new width and height internally, as well as re-allocating
+ the pixel buffer for the new size.
+
+
+
+ void
+
smooth()
+
+
+ If true in PImage, use bilinear interpolation for copy()
+ operations.
+
+
+
+ void
+
sphere(float r)
+
+
+ Draw a sphere with radius r centered at coordinate 0, 0, 0.
Called in response to a resize event, handles setting the
+ new width and height internally, as well as re-allocating
+ the pixel buffer for the new size.
+
+ Note that this will nuke any cameraMode() settings.
+
See notes in PGraphics.
+ If z-sorting has been turned on, then the triangles will
+ all be quicksorted here (to make alpha work more properly)
+ and then blit to the screen.
+
+ For the most part, hints are temporary api quirks,
+ for which a proper api hasn't been properly worked out.
+ for instance SMOOTH_IMAGES existed because smooth()
+ wasn't yet implemented, but it will soon go away.
+
+ They also exist for obscure features in the graphics
+ engine, like enabling/disabling single pixel lines
+ that ignore the zbuffer, the way they do in alphabot.
+
+ Current hint options:
+
+
DISABLE_DEPTH_TEST -
+ turns off the z-buffer in the P3D or OPENGL renderers.
+
+ Differences between beginShape() and line() and point() methods.
+
+ beginShape() is intended to be more flexible at the expense of being
+ a little more complicated to use. it handles more complicated shapes
+ that can consist of many connected lines (so you get joins) or lines
+ mixed with curves.
+
+ The line() and point() command are for the far more common cases
+ (particularly for our audience) that simply need to draw a line
+ or a point on the screen.
+
+ From the code side of things, line() may or may not call beginShape()
+ to do the drawing. In the beta code, they do, but in the alpha code,
+ they did not. they might be implemented one way or the other depending
+ on tradeoffs of runtime efficiency vs. implementation efficiency &mdash
+ meaning the speed that things run at vs. the speed it takes me to write
+ the code and maintain it. for beta, the latter is most important so
+ that's how things are implemented.
+
Draw a sphere with radius r centered at coordinate 0, 0, 0.
+
+ Implementation notes:
+
+ cache all the points of the sphere in a static array
+ top and bottom are just a bunch of triangles that land
+ in the center point
+
+ sphere is a series of concentric circles who radii vary
+ along the shape, based on, er.. cos or something
+
+ [toxi 031031] new sphere code. removed all multiplies with
+ radius, as scale() will take care of that anyway
+
+ [toxi 031223] updated sphere code (removed modulos)
+ and introduced sphereAt(x,y,z,r)
+ to avoid additional translate()'s on the user/sketch side
+
+ [davbol 080801] now using separate sphereDetailU/V
+
Two dimensional rotation. Same as rotateZ (this is identical
+ to a 3D rotation along the z-axis) but included for clarity --
+ it'd be weird for people drawing 2D graphics to be using rotateZ.
+ And they might kick our a-- for the confusion.
+
Rotate around the Z axis.
+
+ The functions rotate() and rotateZ() are identical, it's just that it make
+ sense to have rotate() and then rotateX() and rotateY() when using 3D;
+ nor does it make sense to use a function called rotateZ() if you're only
+ doing things in 2D. so we just decided to have them both be the same.
+
Apply a 4x4 transformation matrix. Same as glMultMatrix().
+ This call will be slow because it will try to calculate the
+ inverse of the transform. So avoid it whenever possible.
+
Set matrix mode to the camera matrix (instead of the current
+ transformation matrix). This means applyMatrix, resetMatrix, etc.
+ will affect the camera.
+
+ Note that the camera matrix is *not* the perspective matrix,
+ it is in front of the modelview matrix (hence the name "model"
+ and "view" for that matrix).
+
+ beginCamera() specifies that all coordinate transforms until endCamera()
+ should be pre-applied in inverse to the camera transform matrix.
+ Note that this is only challenging when a user specifies an arbitrary
+ matrix with applyMatrix(). Then that matrix will need to be inverted,
+ which may not be possible. But take heart, if a user is applying a
+ non-invertible matrix to the camera transform, then he is clearly
+ up to no good, and we can wash our hands of those bad intentions.
+
+ begin/endCamera clauses do not automatically reset the camera transform
+ matrix. That's because we set up a nice default camera transform int
+ setup(), and we expect it to hold through draw(). So we don't reset
+ the camera transform matrix at the top of draw(). That means that an
+ innocuous-looking clause like
+
+ at the top of draw(), will result in a runaway camera that shoots
+ infinitely out of the screen over time. In order to prevent this,
+ it is necessary to call some function that does a hard reset of the
+ camera transform matrix inside of begin/endCamera. Two options are
+
+ camera(); // sets up the nice default camera transform
+ resetMatrix(); // sets up the identity camera transform
+
+ So to rotate a camera a constant amount, you might try
+
Record the current settings into the camera matrix, and set
+ the matrix mode back to the current transformation matrix.
+
+ Note that this will destroy any settings to scale(), translate(),
+ or whatever, because the final camera matrix will be copied
+ (not multiplied) into the modelview.
+
+ Camera behavior can be split into two separate components, camera
+ transformation, and projection. The transformation corresponds to the
+ physical location, orientation, and scale of the camera. In a physical
+ camera metaphor, this is what can manipulated by handling the camera
+ body (with the exception of scale, which doesn't really have a physcial
+ analog). The projection corresponds to what can be changed by
+ manipulating the lens.
+
+ We maintain separate matrices to represent the camera transform and
+ projection. An important distinction between the two is that the camera
+ transform should be invertible, where the projection matrix should not,
+ since it serves to map three dimensions to two. It is possible to bake
+ the two matrices into a single one just by multiplying them together,
+ but it isn't a good idea, since lighting, z-ordering, and z-buffering
+ all demand a true camera z coordinate after modelview and camera
+ transforms have been applied but before projection. If the camera
+ transform and projection are combined there is no way to recover a
+ good camera-space z-coordinate from a model coordinate.
+
+ Fortunately, there are no functions that manipulate both camera
+ transformation and projection.
+
+ camera() sets the camera position, orientation, and center of the scene.
+ It replaces the camera transform with a new one. This is different from
+ gluLookAt(), but I think the only reason that GLU's lookat doesn't fully
+ replace the camera matrix with the new one, but instead multiplies it,
+ is that GL doesn't enforce the separation of camera transform and
+ projection, so it wouldn't be safe (you'd probably stomp your projection).
+
+ The transformation functions are the same ones used to manipulate the
+ modelview matrix (scale, translate, rotate, etc.). But they are bracketed
+ with beginCamera(), endCamera() to indicate that they should apply
+ (in inverse), to the camera transformation matrix.
+
+ This differs considerably from camera transformation in OpenGL.
+ OpenGL only lets you say, apply everything from here out to the
+ projection or modelview matrix. This makes it very hard to treat camera
+ manipulation as if it were a physical camera. Imagine that you want to
+ move your camera 100 units forward. In OpenGL, you need to apply the
+ inverse of that transformation or else you'll move your scene 100 units
+ forward--whether or not you've specified modelview or projection matrix.
+ Remember they're just multiplied by model coods one after another.
+ So in order to treat a camera like a physical camera, it is necessary
+ to pre-apply inverse transforms to a matrix that will be applied to model
+ coordinates. OpenGL provides nothing of this sort, but Processing does!
+ This is the camera transform matrix.
+
+ do not need to be called from with beginCamera();/endCamera();
+ That's because they always apply to the camera transformation,
+ and they always totally replace it. That means that any coordinate
+ transforms done before camera(); in draw() will be wiped out.
+ It also means that camera() always operates in untransformed world
+ coordinates. Therefore it is always redundant to call resetMatrix();
+ before camera(); This isn't technically true of gluLookat, but it's
+ pretty much how it's used.
+
+ Now, beginCamera(); and endCamera(); are useful if you want to move
+ the camera around using transforms like translate(), etc. They will
+ wipe out any coordinate system transforms that occur before them in
+ draw(), but they will not automatically wipe out the camera transform.
+ This means that they should be at the top of draw(). It also means
+ that the following:
+
+ will result in a camera that spins without stopping. If you want to
+ just rotate a small constant amount, try this:
+
+ beginCamera();
+ camera(); // sets up the default view
+ rotateY(PI/8);
+ endCamera();
+
+ That will rotate a little off of the default view. Note that this
+ is entirely equivalent to
+
+ camera(); // sets up the default view
+ beginCamera();
+ rotateY(PI/8);
+ endCamera();
+
+ because camera() doesn't care whether or not it's inside a
+ begin/end clause. Basically it's safe to use camera() or
+ camera(ex, ey, ez, cx, cy, cz, ux, uy, uz) as naked calls because
+ they do all the matrix resetting automatically.
+
Calls perspective() with Processing's standard coordinate projection.
+
+ Projection functions:
+
+
frustrum()
+
ortho()
+
perspective()
+
+ Each of these three functions completely replaces the projection
+ matrix with a new one. They can be called inside setup(), and their
+ effects will be felt inside draw(). At the top of draw(), the projection
+ matrix is not reset. Therefore the last projection function to be
+ called always dominates. On resize, the default projection is always
+ established, which has perspective.
+
+ This behavior is pretty much familiar from OpenGL, except where
+ functions replace matrices, rather than multiplying against the
+ previous.
+
Given an x and y coordinate, returns the x position of where
+ that point would be placed on screen, once affected by translate(),
+ scale(), or any other transformations.
+
Given an x and y coordinate, returns the y position of where
+ that point would be placed on screen, once affected by translate(),
+ scale(), or any other transformations.
+
Maps a three dimensional point to its placement on-screen.
+
+ Given an (x, y, z) coordinate, returns the x position of where
+ that point would be placed on screen, once affected by translate(),
+ scale(), or any other transformations.
+
Maps a three dimensional point to its placement on-screen.
+
+ Given an (x, y, z) coordinate, returns the y position of where
+ that point would be placed on screen, once affected by translate(),
+ scale(), or any other transformations.
+
Maps a three dimensional point to its placement on-screen.
+
+ Given an (x, y, z) coordinate, returns its z value.
+ This value can be used to determine if an (x, y, z) coordinate
+ is in front or in back of another (x, y, z) coordinate.
+ The units are based on how the zbuffer is set up, and don't
+ relate to anything "real". They're only useful for in
+ comparison to another value obtained from screenZ(),
+ or directly out of the zbuffer[].
+
Returns the model space x value for an x, y, z coordinate.
+
+ This will give you a coordinate after it has been transformed
+ by translate(), rotate(), and camera(), but not yet transformed
+ by the projection matrix. For instance, his can be useful for
+ figuring out how points in 3D space relate to the edge
+ coordinates of a shape.
+
+ The Lighting Skinny:
+
+ The way lighting works is complicated enough that it's worth
+ producing a document to describe it. Lighting calculations proceed
+ pretty much exactly as described in the OpenGL red book.
+
+ Light-affecting material properties:
+
+ AMBIENT COLOR
+ - multiplies by light's ambient component
+ - for believability this should match diffuse color
+
+ DIFFUSE COLOR
+ - multiplies by light's diffuse component
+
+ SPECULAR COLOR
+ - multiplies by light's specular component
+ - usually less colored than diffuse/ambient
+
+ SHININESS
+ - the concentration of specular effect
+ - this should be set pretty high (20-50) to see really
+ noticeable specularity
+
+ EMISSIVE COLOR
+ - constant additive color effect
+
+ Light types:
+
+ AMBIENT
+ - one color
+ - no specular color
+ - no direction
+ - may have falloff (constant, linear, and quadratic)
+ - may have position (which matters in non-constant falloff case)
+ - multiplies by a material's ambient reflection
+
+ DIRECTIONAL
+ - has diffuse color
+ - has specular color
+ - has direction
+ - no position
+ - no falloff
+ - multiplies by a material's diffuse and specular reflections
+
+ POINT
+ - has diffuse color
+ - has specular color
+ - has position
+ - no direction
+ - may have falloff (constant, linear, and quadratic)
+ - multiplies by a material's diffuse and specular reflections
+
+ SPOT
+ - has diffuse color
+ - has specular color
+ - has position
+ - has direction
+ - has cone angle (set to half the total cone angle)
+ - has concentration value
+ - may have falloff (constant, linear, and quadratic)
+ - multiplies by a material's diffuse and specular reflections
+
+ Normal modes:
+
+ All of the primitives (rect, box, sphere, etc.) have their normals
+ set nicely. During beginShape/endShape normals can be set by the user.
+
+ AUTO-NORMAL
+ - if no normal is set during the shape, we are in auto-normal mode
+ - auto-normal calculates one normal per triangle (face-normal mode)
+
+ SHAPE-NORMAL
+ - if one normal is set during the shape, it will be used for
+ all vertices
+
+ VERTEX-NORMAL
+ - if multiple normals are set, each normal applies to
+ subsequent vertices
+ - (except for the first one, which applies to previous
+ and subsequent vertices)
+
+ Efficiency consequences:
+
+ There is a major efficiency consequence of position-dependent
+ lighting calculations per vertex. (See below for determining
+ whether lighting is vertex position-dependent.) If there is no
+ position dependency then the only factors that affect the lighting
+ contribution per vertex are its colors and its normal.
+ There is a major efficiency win if
+
+ 1) lighting is not position dependent
+ 2) we are in AUTO-NORMAL or SHAPE-NORMAL mode
+
+ because then we can calculate one lighting contribution per shape
+ (SHAPE-NORMAL) or per triangle (AUTO-NORMAL) and simply multiply it
+ into the vertex colors. The converse is our worst-case performance when
+
+ 1) lighting is position dependent
+ 2) we are in AUTO-NORMAL mode
+
+ because then we must calculate lighting per-face * per-vertex.
+ Each vertex has a different lighting contribution per face in
+ which it appears. Yuck.
+
+ Determining vertex position dependency:
+
+ If any of the following factors are TRUE then lighting is
+ vertex position dependent:
+
+ 1) Any lights uses non-constant falloff
+ 2) There are any point or spot lights
+ 3) There is a light with specular color AND there is a
+ material with specular color
+
+ So worth noting is that default lighting (a no-falloff ambient
+ and a directional without specularity) is not position-dependent.
+ We should capitalize.
+
+ Simon Greenwold, April 2005
+
Add an ambient light based on the current color mode.
+ This version includes an (x, y, z) position for situations
+ where the falloff distance is used.
+
+Subclass for PGraphics that implements the graphics API using Java2D.
+
+
Pixel operations too slow? As of release 0085 (the first beta),
+ the default renderer uses Java2D. It's more accurate than the renderer
+ used in alpha releases of Processing (it handles stroke caps and joins,
+ and has better polygon tessellation), but it's super slow for handling
+ pixels. At least until we get a chance to get the old 2D renderer
+ (now called P2D) working in a similar fashion, you can use
+ size(w, h, P3D) instead of size(w, h) which will
+ be faster for general pixel flipping madness.
+
+
To get access to the Java 2D "Graphics2D" object for the default
+ renderer, use:
+
Graphics2D g2 = ((PGraphicsJava2D)g).g2;
+ This will let you do Java 2D stuff directly, but is not supported in
+ any way shape or form. Which just means "have fun, but don't complain
+ if it breaks."
breakShape()
+
+
+ This feature is in testing, do not use or rely upon its implementation
+
+
+
+ boolean
+
canDraw()
+
+
+ Some renderers have requirements re: when they are ready to draw.
+
+
+
+ void
+
copy(int sx,
+ int sy,
+ int sw,
+ int sh,
+ int dx,
+ int dy,
+ int dw,
+ int dh)
+
+
+ Copy things from one area of this image
+ to another area in the same image.
getImpl(int x,
+ int y,
+ int w,
+ int h)
+
+
+ Internal function to actually handle getting a block of pixels that
+ has already been properly cropped to a valid region.
scale(float sx,
+ float sy)
+
+
+ Scale in X and Y.
+
+
+
+ void
+
scale(float sx,
+ float sy,
+ float sz)
+
+
+ Scale in X, Y, and Z.
+
+
+
+ float
+
screenX(float x,
+ float y)
+
+
+ Given an x and y coordinate, returns the x position of where
+ that point would be placed on screen, once affected by translate(),
+ scale(), or any other transformations.
+
+
+
+ float
+
screenX(float x,
+ float y,
+ float z)
+
+
+ Maps a three dimensional point to its placement on-screen.
+
+
+
+ float
+
screenY(float x,
+ float y)
+
+
+ Given an x and y coordinate, returns the y position of where
+ that point would be placed on screen, once affected by translate(),
+ scale(), or any other transformations.
+
+
+
+ float
+
screenY(float x,
+ float y,
+ float z)
+
+
+ Maps a three dimensional point to its placement on-screen.
+
+
+
+ float
+
screenZ(float x,
+ float y,
+ float z)
+
+
+ Maps a three dimensional point to its placement on-screen.
+
+
+
+ void
+
set(int x,
+ int y,
+ int argb)
+
+
+ Set a single pixel to the specified color.
+
+
+
+ void
+
setMatrix(PMatrix2D source)
+
+
+ Set the current transformation to the contents of the specified source.
+
+
+
+ void
+
setMatrix(PMatrix3D source)
+
+
+ Set the current transformation to the contents of the specified source.
+
+
+
+ void
+
setSize(int iwidth,
+ int iheight)
+
+
+ Called in response to a resize event, handles setting the
+ new width and height internally, as well as re-allocating
+ the pixel buffer for the new size.
+
+
+
+ void
+
smooth()
+
+
+ If true in PImage, use bilinear interpolation for copy()
+ operations.
+
+
+
+ void
+
sphere(float r)
+
+
+ Draw a sphere with radius r centered at coordinate 0, 0, 0.
Called in response to a resize event, handles setting the
+ new width and height internally, as well as re-allocating
+ the pixel buffer for the new size.
+
+ Note that this will nuke any cameraMode() settings.
+
This will finalize rendering so that it can be shown on-screen.
+
+ When creating your own PGraphics, you should call this when
+ you're finished drawing.
+
+ Differences between beginShape() and line() and point() methods.
+
+ beginShape() is intended to be more flexible at the expense of being
+ a little more complicated to use. it handles more complicated shapes
+ that can consist of many connected lines (so you get joins) or lines
+ mixed with curves.
+
+ The line() and point() command are for the far more common cases
+ (particularly for our audience) that simply need to draw a line
+ or a point on the screen.
+
+ From the code side of things, line() may or may not call beginShape()
+ to do the drawing. In the beta code, they do, but in the alpha code,
+ they did not. they might be implemented one way or the other depending
+ on tradeoffs of runtime efficiency vs. implementation efficiency &mdash
+ meaning the speed that things run at vs. the speed it takes me to write
+ the code and maintain it. for beta, the latter is most important so
+ that's how things are implemented.
+
Draw a sphere with radius r centered at coordinate 0, 0, 0.
+
+ Implementation notes:
+
+ cache all the points of the sphere in a static array
+ top and bottom are just a bunch of triangles that land
+ in the center point
+
+ sphere is a series of concentric circles who radii vary
+ along the shape, based on, er.. cos or something
+
+ [toxi 031031] new sphere code. removed all multiplies with
+ radius, as scale() will take care of that anyway
+
+ [toxi 031223] updated sphere code (removed modulos)
+ and introduced sphereAt(x,y,z,r)
+ to avoid additional translate()'s on the user/sketch side
+
+ [davbol 080801] now using separate sphereDetailU/V
+
Returns the ascent of the current font at the current size.
+ This is a method, rather than a variable inside the PGraphics object
+ because it requires calculation.
+
Returns the descent of the current font at the current size.
+ This is a method, rather than a variable inside the PGraphics object
+ because it requires calculation.
+
Two dimensional rotation.
+
+ Same as rotateZ (this is identical to a 3D rotation along the z-axis)
+ but included for clarity. It'd be weird for people drawing 2D graphics
+ to be using rotateZ. And they might kick our a-- for the confusion.
+
+ Additional background.
+
Rotate around the Z axis.
+
+ The functions rotate() and rotateZ() are identical, it's just that it make
+ sense to have rotate() and then rotateX() and rotateY() when using 3D;
+ nor does it make sense to use a function called rotateZ() if you're only
+ doing things in 2D. so we just decided to have them both be the same.
+
Scale in X and Y. Equivalent to scale(sx, sy, 1).
+
+ Not recommended for use in 3D, because the z-dimension is just
+ scaled by 1, since there's no way to know what else to scale it by.
+
Given an x and y coordinate, returns the x position of where
+ that point would be placed on screen, once affected by translate(),
+ scale(), or any other transformations.
+
Given an x and y coordinate, returns the y position of where
+ that point would be placed on screen, once affected by translate(),
+ scale(), or any other transformations.
+
Maps a three dimensional point to its placement on-screen.
+
+ Given an (x, y, z) coordinate, returns the x position of where
+ that point would be placed on screen, once affected by translate(),
+ scale(), or any other transformations.
+
Maps a three dimensional point to its placement on-screen.
+
+ Given an (x, y, z) coordinate, returns the y position of where
+ that point would be placed on screen, once affected by translate(),
+ scale(), or any other transformations.
+
Maps a three dimensional point to its placement on-screen.
+
+ Given an (x, y, z) coordinate, returns its z value.
+ This value can be used to determine if an (x, y, z) coordinate
+ is in front or in back of another (x, y, z) coordinate.
+ The units are based on how the zbuffer is set up, and don't
+ relate to anything "real". They're only useful for in
+ comparison to another value obtained from screenZ(),
+ or directly out of the zbuffer[].
+
Actual implementation of clearing the background, now that the
+ internal variables for background color have been set. Called by the
+ backgroundFromCalc() method, which is what all the other background()
+ methods call once the work is done.
+
Call this when you want to mess with the pixels[] array.
+
+ For subclasses where the pixels[] buffer isn't set by default,
+ this should copy all data into the pixels[] array
+
Returns an ARGB "color" type (a packed 32 bit int with the color.
+ If the coordinate is outside the image, zero is returned
+ (black, but completely transparent).
+
+ If the image is in RGB format (i.e. on a PVideo object),
+ the value will get its high bits set, just to avoid cases where
+ they haven't been set already.
+
+ If the image is in ALPHA format, this returns a white with its
+ alpha value set.
+
+ This function is included primarily for beginners. It is quite
+ slow because it has to check to see if the x, y that was provided
+ is inside the bounds, and then has to check to see what image
+ type it is. If you want things to be more efficient, access the
+ pixels[] array directly.
+
Internal function to actually handle getting a block of pixels that
+ has already been properly cropped to a valid region. That is, x/y/w/h
+ are guaranteed to be inside the image space, so the implementation can
+ use the fastest possible pixel copying method.
+
Set alpha channel for an image. Black colors in the source
+ image will make the destination image completely transparent,
+ and white will make things fully opaque. Gray values will
+ be in-between steps.
+
+ Strictly speaking the "blue" value from the source image is
+ used as the alpha color. For a fully grayscale image, this
+ is correct, but for a color image it's not 100% accurate.
+ For a more accurate conversion, first use filter(GRAY)
+ which will make the image into a "correct" grayscake by
+ performing a proper luminance-based conversion.
+
PImage()
+
+
+ Create an empty image object, set its format to RGB.
+
+
+
PImage(java.awt.Image img)
+
+
+ Construct a new PImage from a java.awt.Image.
+
+
+
PImage(int width,
+ int height)
+
+
+ Create a new RGB (alpha ignored) image of a specific size.
+
+
+
PImage(int width,
+ int height,
+ int format)
+
+
+
+
+
+
+
+
+
+
+
+
+Method Summary
+
+
+
+ void
+
blend(int sx,
+ int sy,
+ int sw,
+ int sh,
+ int dx,
+ int dy,
+ int dw,
+ int dh,
+ int mode)
+
+
+ Blends one area of this image to another area.
+
+
+
+ void
+
blend(PImage src,
+ int sx,
+ int sy,
+ int sw,
+ int sh,
+ int dx,
+ int dy,
+ int dw,
+ int dh,
+ int mode)
+
+
+ Copies area of one image into another PImage object.
+
+
+
+static int
+
blendColor(int c1,
+ int c2,
+ int mode)
+
+
+ Blend two colors based on a particular mode.
+
+
+
+ java.lang.Object
+
clone()
+
+
+ Duplicate an image, returns new PImage object.
+
+
+
+ void
+
copy(int sx,
+ int sy,
+ int sw,
+ int sh,
+ int dx,
+ int dy,
+ int dw,
+ int dh)
+
+
+ Copy things from one area of this image
+ to another area in the same image.
+
+
+
+ void
+
copy(PImage src,
+ int sx,
+ int sy,
+ int sw,
+ int sh,
+ int dx,
+ int dy,
+ int dw,
+ int dh)
+
+
+ Copies area of one image into another PImage object.
+
+
+
+ void
+
filter(int kind)
+
+
+ Method to apply a variety of basic filters to this image.
+
+
+
+ void
+
filter(int kind,
+ float param)
+
+
+ Method to apply a variety of basic filters to this image.
get(int x,
+ int y,
+ int w,
+ int h)
+
+
+ Grab a subsection of a PImage, and copy it into a fresh PImage.
+
+
+
+ java.lang.Object
+
getCache(java.lang.Object parent)
+
+
+ Get cache storage data for the specified renderer.
+
+
+
+ java.awt.Image
+
getImage()
+
+
+ Returns a BufferedImage from this PImage.
+
+
+
+ void
+
init(int width,
+ int height,
+ int format)
+
+
+ Function to be used by subclasses of PImage to init later than
+ at the constructor, or re-init later when things changes.
loadPixels()
+
+
+ Call this when you want to mess with the pixels[] array.
+
+
+
+ void
+
mask(int[] alpha)
+
+
+ Set alpha channel for an image.
+
+
+
+ void
+
mask(PImage alpha)
+
+
+ Set alpha channel for an image using another image as the source.
+
+
+
+ void
+
removeCache(java.lang.Object parent)
+
+
+ Remove information associated with this renderer from the cache, if any.
+
+
+
+ void
+
resize(int wide,
+ int high)
+
+
+ Resize this image to a new width and height.
+
+
+
+ void
+
save(java.lang.String path)
+
+
+ Save this image to disk.
+
+
+
+ void
+
set(int x,
+ int y,
+ int c)
+
+
+ Set a single pixel to the specified color.
+
+
+
+ void
+
set(int x,
+ int y,
+ PImage src)
+
+
+ Efficient method of drawing an image's pixels directly to this surface.
+
+
+
+ void
+
setCache(java.lang.Object parent,
+ java.lang.Object storage)
+
+
+ Store data of some kind for a renderer that requires extra metadata of
+ some kind.
Format for this image, one of RGB, ARGB or ALPHA.
+ note that RGB images still require 0xff in the high byte
+ because of how they'll be manipulated by other functions
+
Path to parent object that will be used with save().
+ This prevents users from needing savePath() to use PImage.save().
+
+
+
+
+
+
+
+
+
+
+
+Constructor Detail
+
+
+
+
+PImage
+
+public PImage()
+
+
Create an empty image object, set its format to RGB.
+ The pixel array is not allocated.
+
+
+
+
+
+PImage
+
+public PImage(int width,
+ int height)
+
+
Create a new RGB (alpha ignored) image of a specific size.
+ All pixels are set to zero, meaning black, but since the
+ alpha is zero, it will be transparent.
+
+
+
+
+
+PImage
+
+public PImage(int width,
+ int height,
+ int format)
+
+
+
+
+
+PImage
+
+public PImage(java.awt.Image img)
+
+
Construct a new PImage from a java.awt.Image. This constructor assumes
+ that you've done the work of making sure a MediaTracker has been used
+ to fully download the data and that the img is valid.
+
+
+
+
+
+
+
+
+
+Method Detail
+
+
+
+
+init
+
+public void init(int width,
+ int height,
+ int format)
+
+
Function to be used by subclasses of PImage to init later than
+ at the constructor, or re-init later when things changes.
+ Used by Capture and Movie classes (and perhaps others),
+ because the width/height will not be known when super() is called.
+ (Leave this public so that other libraries can do the same.)
+
Store data of some kind for a renderer that requires extra metadata of
+ some kind. Usually this is a renderer-specific representation of the
+ image data, for instance a BufferedImage with tint() settings applied for
+ PGraphicsJava2D, or resized image data and OpenGL texture indices for
+ PGraphicsOpenGL.
+
Get cache storage data for the specified renderer. Because each renderer
+ will cache data in different formats, it's necessary to store cache data
+ keyed by the renderer object. Otherwise, attempting to draw the same
+ image to both a PGraphicsJava2D and a PGraphicsOpenGL will cause errors.
+
+
+
+
+
+
Parameters:
parent - The PGraphics object (or any object, really) associated
+
Returns:
data stored for the specified parent
+
+
+
+
+
+removeCache
+
+public void removeCache(java.lang.Object parent)
+
+
Remove information associated with this renderer from the cache, if any.
+
+
+
+
+
+
Parameters:
parent - The PGraphics object whose cache data should be removed
+
+
+
+
+
+isModified
+
+public boolean isModified()
+
+
+
+
+
+
+
+
+
+
+
+setModified
+
+public void setModified()
+
+
+
+
+
+
+
+
+
+
+
+setModified
+
+public void setModified(boolean m)
+
+
+
+
+
+
+
+
+
+
+
+loadPixels
+
+public void loadPixels()
+
+
Call this when you want to mess with the pixels[] array.
+
+ For subclasses where the pixels[] buffer isn't set by default,
+ this should copy all data into the pixels[] array
+
+
+
+
+
+
+
+
+
+
+
+updatePixels
+
+public void updatePixels()
+
+
Call this when finished messing with the pixels[] array.
+
+ Mark all pixels as needing update.
+
+
+
+
+
+
+
+
+
+
+
+updatePixels
+
+public void updatePixels(int x,
+ int y,
+ int w,
+ int h)
+
+
Mark the pixels in this region as needing an update.
+
+ This is not currently used by any of the renderers, however the api
+ is structured this way in the hope of being able to use this to
+ speed things up in the future.
+
Duplicate an image, returns new PImage object.
+ The pixels[] array for the new object will be unique
+ and recopied from the source image. This is implemented as an
+ override of Object.clone(). We recommend using get() instead,
+ because it prevents you from needing to catch the
+ CloneNotSupportedException, and from doing a cast from the result.
+
+
+
Overrides:
clone in class java.lang.Object
+
+
+
+
Throws:
+
java.lang.CloneNotSupportedException
+
+
+
+
+
+resize
+
+public void resize(int wide,
+ int high)
+
+
Resize this image to a new width and height.
+ Use 0 for wide or high to make that dimension scale proportionally.
+
+
+
+
+
+
+
+
+
+
+
+get
+
+public int get(int x,
+ int y)
+
+
Returns an ARGB "color" type (a packed 32 bit int with the color.
+ If the coordinate is outside the image, zero is returned
+ (black, but completely transparent).
+
+ If the image is in RGB format (i.e. on a PVideo object),
+ the value will get its high bits set, just to avoid cases where
+ they haven't been set already.
+
+ If the image is in ALPHA format, this returns a white with its
+ alpha value set.
+
+ This function is included primarily for beginners. It is quite
+ slow because it has to check to see if the x, y that was provided
+ is inside the bounds, and then has to check to see what image
+ type it is. If you want things to be more efficient, access the
+ pixels[] array directly.
+
+
+
+
+
+
+
+
+
+
+
+get
+
+public PImageget(int x,
+ int y,
+ int w,
+ int h)
+
+
Grab a subsection of a PImage, and copy it into a fresh PImage.
+ As of release 0149, no longer honors imageMode() for the coordinates.
+
Efficient method of drawing an image's pixels directly to this surface.
+ No variations are employed, meaning that any scale, tint, or imageMode
+ settings will be ignored.
+
+
+
+
+
+
+
+
+
+
+
+mask
+
+public void mask(int[] alpha)
+
+
Set alpha channel for an image. Black colors in the source
+ image will make the destination image completely transparent,
+ and white will make things fully opaque. Gray values will
+ be in-between steps.
+
+ Strictly speaking the "blue" value from the source image is
+ used as the alpha color. For a fully grayscale image, this
+ is correct, but for a color image it's not 100% accurate.
+ For a more accurate conversion, first use filter(GRAY)
+ which will make the image into a "correct" grayscake by
+ performing a proper luminance-based conversion.
+
Set alpha channel for an image using another image as the source.
+
+
+
+
+
+
+
+
+
+
+
+filter
+
+public void filter(int kind)
+
+
Method to apply a variety of basic filters to this image.
+
+
+
filter(BLUR) provides a basic blur.
+
filter(GRAY) converts the image to grayscale based on luminance.
+
filter(INVERT) will invert the color components in the image.
+
filter(OPAQUE) set all the high bits in the image to opaque
+
filter(THRESHOLD) converts the image to black and white.
+
filter(DILATE) grow white/light areas
+
filter(ERODE) shrink white/light areas
+
+ Luminance conversion code contributed by
+ toxi
+
+ Gaussian blur code contributed by
+ Mario Klingemann
+
+
+
+
+
+
+
+
+
+
+
+filter
+
+public void filter(int kind,
+ float param)
+
+
Method to apply a variety of basic filters to this image.
+ These filters all take a parameter.
+
+
+
filter(BLUR, int radius) performs a gaussian blur of the
+ specified radius.
+
filter(POSTERIZE, int levels) will posterize the image to
+ between 2 and 255 levels.
+
filter(THRESHOLD, float center) allows you to set the
+ center point for the threshold. It takes a value from 0 to 1.0.
+
+ Gaussian blur code contributed by
+ Mario Klingemann
+ and later updated by toxi for better speed.
+
+
+
+
+
+
+
+
+
+
+
+copy
+
+public void copy(int sx,
+ int sy,
+ int sw,
+ int sh,
+ int dx,
+ int dy,
+ int dw,
+ int dh)
+
+
Copy things from one area of this image
+ to another area in the same image.
+
+
+
+
+
+
+
+
+
+
+
+copy
+
+public void copy(PImage src,
+ int sx,
+ int sy,
+ int sw,
+ int sh,
+ int dx,
+ int dy,
+ int dw,
+ int dh)
+
+
Copies area of one image into another PImage object.
+
+
+
+
+
+
+
+
+
+
+
+blendColor
+
+public static int blendColor(int c1,
+ int c2,
+ int mode)
+
+
Blend two colors based on a particular mode.
+
+
REPLACE - destination colour equals colour of source pixel: C = A.
+ Sometimes called "Normal" or "Copy" in other software.
+
+
BLEND - linear interpolation of colours:
+ C = A*factor + B
+
+
ADD - additive blending with white clip:
+ C = min(A*factor + B, 255).
+ Clipped to 0..255, Photoshop calls this "Linear Burn",
+ and Director calls it "Add Pin".
+
+
SUBTRACT - substractive blend with black clip:
+ C = max(B - A*factor, 0).
+ Clipped to 0..255, Photoshop calls this "Linear Dodge",
+ and Director calls it "Subtract Pin".
+
+
DARKEST - only the darkest colour succeeds:
+ C = min(A*factor, B).
+ Illustrator calls this "Darken".
+
+
LIGHTEST - only the lightest colour succeeds:
+ C = max(A*factor, B).
+ Illustrator calls this "Lighten".
+
+
DIFFERENCE - subtract colors from underlying image.
+
+
EXCLUSION - similar to DIFFERENCE, but less extreme.
+
+
MULTIPLY - Multiply the colors, result will always be darker.
+
+
SCREEN - Opposite multiply, uses inverse values of the colors.
+
+
OVERLAY - A mix of MULTIPLY and SCREEN. Multiplies dark values,
+ and screens light values.
+
+
HARD_LIGHT - SCREEN when greater than 50% gray, MULTIPLY when lower.
+
+
SOFT_LIGHT - Mix of DARKEST and LIGHTEST.
+ Works like OVERLAY, but not as harsh.
+
+
DODGE - Lightens light tones and increases contrast, ignores darks.
+ Called "Color Dodge" in Illustrator and Photoshop.
+
+
BURN - Darker areas are applied, increasing contrast, ignores lights.
+ Called "Color Burn" in Illustrator and Photoshop.
+
+
A useful reference for blending modes and their algorithms can be
+ found in the SVG
+ specification.
+
It is important to note that Processing uses "fast" code, not
+ necessarily "correct" code. No biggie, most software does. A nitpicker
+ can find numerous "off by 1 division" problems in the blend code where
+ >>8 or >>7 is used when strictly speaking
+ /255.0 or /127.0 should have been used.
+
For instance, exclusion (not intended for real-time use) reads
+ r1 + r2 - ((2 * r1 * r2) / 255) because 255 == 1.0
+ not 256 == 1.0. In other words, (255*255)>>8 is not
+ the same as (255*255)/255. But for real-time use the shifts
+ are preferrable, and the difference is insignificant for applications
+ built with Processing.
+
+
+
+
+
+
+
+
+
+
+
+blend
+
+public void blend(int sx,
+ int sy,
+ int sw,
+ int sh,
+ int dx,
+ int dy,
+ int dw,
+ int dh,
+ int mode)
+ As of revision 0100, this function requires an absolute path,
+ in order to avoid confusion. To save inside the sketch folder,
+ use the function savePath() from PApplet, or use saveFrame() instead.
+ As of revision 0116, savePath() is not needed if this object has been
+ created (as recommended) via createImage() or createGraphics() or
+ one of its neighbors.
+
+ As of revision 0115, when using Java 1.4 and later, you can write
+ to several formats besides tga and tiff. If Java 1.4 is installed
+ and the extension used is supported (usually png, jpg, jpeg, bmp,
+ and tiff), then those methods will be used to write the image.
+ To get a list of the supported formats for writing, use:
+ println(javax.imageio.ImageIO.getReaderFormatNames())
+
+ To use the original built-in image writers, use .tga or .tif as the
+ extension, or don't include an extension. When no extension is used,
+ the extension .tif will be added to the file name.
+
+ The ImageIO API claims to support wbmp files, however they probably
+ require a black and white image. Basic testing produced a zero-length
+ file with no error.
+
Multiply a two element vector against this matrix.
+ If out is null or not length four, a new float array will be returned.
+ The values for vec and out can be the same (though that's less efficient).
+
+In-progress class to handle shape data, currently to be considered of
+ alpha or beta quality. Major structural work may be performed on this class
+ after the release of Processing 1.0. Such changes may include:
+
+
+
addition of proper accessors to read shape vertex and coloring data
+ (this is the second most important part of having a PShape class after all).
+
a means of creating PShape objects ala beginShape() and endShape().
+
load(), update(), and cache methods ala PImage, so that shapes can
+ have renderer-specific optimizations, such as vertex arrays in OpenGL.
+
splitting this class into multiple classes to handle different
+ varieties of shape data (primitives vs collections of vertices vs paths)
+
change of package declaration, for instance moving the code into
+ package processing.shape (if the code grows too much).
+
+
+
For the time being, this class and its shape() and loadShape() friends in
+ PApplet exist as placeholders for more exciting things to come. If you'd
+ like to work with this class, make a subclass (see how PShapeSVG works)
+ and you can play with its internal methods all you like.
+
+
Library developers are encouraged to create PShape objects when loading
+ shape data, so that they can eventually hook into the bounty that will be
+ the PShape interface, and the ease of loadShape() and shape().
findChild(java.lang.String target)
+
+
+ Same as getChild(name), except that it first walks all the way up the
+ hierarchy to the farthest parent, so that children can be found anywhere.
Overrides this shape's style information and uses PGraphics styles and
+ colors. Identical to ignoreStyles(true). Also disables styles for all
+ child shapes.
+
+
+
+
+
+
+
+
+
+
+
+enableStyle
+
+public void enableStyle()
+
+
Re-enables style information (fill and stroke) set in the shape.
+
+
+
+
+
+
+
+
+
+
+
+getWidth
+
+public float getWidth()
+
+
Get the width of the drawing area (not necessarily the shape boundary).
+
+
+
+
+
+
+
+
+
+
+
+getHeight
+
+public float getHeight()
+
+
Get the height of the drawing area (not necessarily the shape boundary).
+
+SVG stands for Scalable Vector Graphics, a portable graphics format. It is
+ a vector format so it allows for infinite resolution and relatively small
+ file sizes. Most modern media software can view SVG files, including Adobe
+ products, Firefox, etc. Illustrator and Inkscape can edit SVG files.
+
+ We have no intention of turning this into a full-featured SVG library.
+ The goal of this project is a basic shape importer that is small enough
+ to be included with applets, meaning that its download size should be
+ in the neighborhood of 25-30k. Starting with release 0149, this library
+ has been incorporated into the core via the loadShape() command, because
+ vector shape data is just as important as the image data from loadImage().
+
+ For more sophisticated import/export, consider the
+ Batik
+ library from the Apache Software Foundation. Future improvements to this
+ library may focus on this properly supporting a specific subset of SVG,
+ for instance the simpler SVG profiles known as
+ SVG Tiny or Basic,
+ although we still would not support the interactivity options.
+
+
+
+ A minimal example program using SVG:
+ (assuming a working moo.svg is in your data folder)
+
+
+
+ This code is based on the Candy library written by Michael Chang, which was
+ later revised and expanded for use as a Processing core library by Ben Fry.
+ Thanks to Ricard Marxer Pinon for help with better Inkscape support in 0154.
+
+
+
+ Late October 2008 revisions from ricardmp, incorporated by fry (0154)
+
Get a particular element based on its SVG ID. When editing SVG by hand,
+ this is the id="" tag on any SVG element. When editing from Illustrator,
+ these IDs can be edited by expanding the layers palette. The names used
+ in the layers palette, both for the layers or the shapes and groups
+ beneath them can be used here.
+
+ // This code grabs "Layer 3" and the shapes beneath it.
+ SVG layer3 = svg.getChild("Layer 3");
+
+Smoothed triangle renderer for P3D.
+
+ Based off of the PPolygon class in old versions of Processing.
+ Name and location of this class will change in a future release.
+
+
+
+
+
+
+
+
+
+
+
+
+Field Summary
+
+
+
+
+
+
Fields inherited from interface processing.core.PConstants
Pass camera-space coordinates for the triangle.
+ Needed to render if hint(ENABLE_ACCURATE_TEXTURES) enabled.
+ Generally this will not need to be called manually,
+ currently called from PGraphics3D.render_triangles()
+
Pass camera-space coordinates for the triangle.
+ Needed to render if hint(ENABLE_ACCURATE_TEXTURES) enabled.
+ Generally this will not need to be called manually,
+ currently called from PGraphics3D.render_triangles()
+
Set the power of two used for linear interpolation of texture coordinates.
+ A true texture coordinate is computed every 2^pwr pixels along a scanline.
+
+A class to describe a two or three dimensional vector.
+
+ The result of all functions are applied to the vector itself, with the
+ exception of cross(), which returns a new PVector (or writes to a specified
+ 'target' PVector). That is, add() will add the contents of one vector to
+ this one. Using add() with additional parameters allows you to put the
+ result into a new PVector. Functions that act on multiple vectors also
+ include static versions. Because creating new objects can be computationally
+ expensive, most functions include an optional 'target' PVector, so that a
+ new PVector object is not created with each operation.
+
+ Initially based on the Vector3D class by Dan Shiffman.
+
div(PVector v1,
+ PVector v2)
+
+
+ Multiply each element of one vector by the individual elements of another
+ vector, and return the result as a new PVector.
div(PVector v1,
+ PVector v2,
+ PVector target)
+
+
+ Divide each element of one vector by the individual elements of another
+ vector, and write the result into a target vector.
mult(PVector v1,
+ PVector v2)
+
+
+ Multiply each element of one vector by the individual elements of another
+ vector, and return the result as a new PVector.
mult(PVector v1,
+ PVector v2,
+ PVector target)
+
+
+ Multiply each element of one vector by the individual elements of another
+ vector, and write the result into a target vector.
+
+
+
+ void
+
normalize()
+
+
+ Normalize the vector to length 1 (make it a unit vector)
Calculate the angle between two vectors, using the dot product
+
+
+
Parameters:
v1 - a vector
v2 - another vector
+
Returns:
the angle between the vectors
+
+
+
+
+
+toString
+
+public java.lang.String toString()
+
+
+
Overrides:
toString in class java.lang.Object
+
+
+
+
+
+
+
+
+array
+
+public float[] array()
+
+
Return a representation of this vector as a float array. This is only for
+ temporary use. If used in any other fashion, the contents should be copied
+ by using the get() command to copy into your own array.
+
+A simple library to write DXF files with Processing.
+ Because this is used with beginRaw() and endRaw(), only individual
+ triangles and (discontinuous) line segments will be written to the file.
+
+ Use something like a keyPressed() in PApplet to trigger it,
+ to avoid writing a bazillion .dxf files.
+
+ Usually, the file will be saved to the sketch's folder.
+ Use Sketch → Show Sketch Folder to see it from the PDE.
+
+ A simple example of how to use:
+
+ import processing.dxf.*;
+
+ boolean record;
+
+ void setup() {
+ size(500, 500, P3D);
+ }
+
+ void keyPressed() {
+ // use a key press so that it doesn't make a million files
+ if (key == 'r') record = true;
+ }
+
+ void draw() {
+ if (record) {
+ beginRaw(DXF, "output.dxf");
+ }
+
+ // do all your drawing here
+
+ if (record) {
+ endRaw();
+ record = false;
+ }
+ }
+
+ or to use it and be able to control the current layer:
+
+ import processing.dxf.*;
+
+ boolean record;
+ RawDXF dxf;
+
+ void setup() {
+ size(500, 500, P3D);
+ }
+
+ void keyPressed() {
+ // use a key press so that it doesn't make a million files
+ if (key == 'r') record = true;
+ }
+
+ void draw() {
+ if (record) {
+ dxf = (RawDXF) createGraphics(width, height, DXF, "output.dxf");
+ beginRaw(dxf);
+ }
+
+ // do all your drawing here, and to set the layer, call:
+ // if (record) {
+ // dxf.setLayer(num);
+ // }
+ // where 'num' is an integer.
+ // the default is zero, or you can set it to whatever.
+
+ if (record) {
+ endRaw();
+ record = false;
+ dxf = null;
+ }
+ }
+
+ Note that even though this class is a subclass of PGraphics, it only
+ implements the parts of the API that are necessary for beginRaw/endRaw.
+
+ Based on the original DXF writer from Simon Greenwold, February 2004.
+ Updated for Processing 0070 by Ben Fry in September 2004,
+ and again for Processing beta in April 2005.
+ Rewritten to support beginRaw/endRaw by Ben Fry in February 2006.
+ Updated again for inclusion as a core library in March 2006.
+ Constructor modifications in September 2008 as we approach 1.0.
+
+
+
+
+
+
+
+
+
+
+
+
+Field Summary
+
+
+
+
+
+
Fields inherited from class processing.core.PGraphics3D
+ This is called when a sketch is shut down and this renderer was
+ specified using the size() command, or inside endRecord() and
+ endRaw(), in order to shut things off.
+
Return true if this renderer should be drawn to the screen. Defaults to
+ returning true, since nearly all renderers are on-screen beasts. But can
+ be overridden for subclasses like PDF so that a window doesn't open up.
+
+ A better name? showFrame, displayable, isVisible, visible, shouldDisplay,
+ what to call this?
+
See notes in PGraphics.
+ If z-sorting has been turned on, then the triangles will
+ all be quicksorted here (to make alpha work more properly)
+ and then blit to the screen.
+
Write a command on one line (as a String), then start a new line
+ and write out a formatted float. Available for anyone who wants to
+ insert additional commands into the DXF stream.
+
+
+
+
+
+
+
+
+println
+
+public void println(java.lang.String what)
+
+
Write a line to the dxf file. Available for anyone who wants to
+ insert additional commands into the DXF stream.
+
+ Differences between beginShape() and line() and point() methods.
+
+ beginShape() is intended to be more flexible at the expense of being
+ a little more complicated to use. it handles more complicated shapes
+ that can consist of many connected lines (so you get joins) or lines
+ mixed with curves.
+
+ The line() and point() command are for the far more common cases
+ (particularly for our audience) that simply need to draw a line
+ or a point on the screen.
+
+ From the code side of things, line() may or may not call beginShape()
+ to do the drawing. In the beta code, they do, but in the alpha code,
+ they did not. they might be implemented one way or the other depending
+ on tradeoffs of runtime efficiency vs. implementation efficiency &mdash
+ meaning the speed that things run at vs. the speed it takes me to write
+ the code and maintain it. for beta, the latter is most important so
+ that's how things are implemented.
+
Disconnect from the server and calls disconnectEvent(Client c)
+ in the host PApplet.
+
+ Use this to shut the connection if you're finished with it
+ while your applet is still running. Otherwise, it will be
+ automatically be shut down by the host PApplet
+ (using dispose, which is identical)
+
+
+
+
+
+
+
+
+
+
+
+dispose
+
+public void dispose()
+
+
Disconnect from the server: internal use only.
+
+ This should only be called by the internal functions in PApplet,
+ use stop() instead from within your own applets.
+
+
+
+
+
+
+
+
+
+
+
+run
+
+public void run()
+
+
+
Specified by:
run in interface java.lang.Runnable
+
+
+
+
+
+
+
+
+active
+
+public boolean active()
+
+
Return true if this client is still active and hasn't run
+ into any trouble.
+
+
+
+
+
+
+
+
+
+
+
+ip
+
+public java.lang.String ip()
+
+
Returns the ip address of this feller as a String.
+
+
+
+
+
+
+
+
+
+
+
+available
+
+public int available()
+
+
Returns the number of bytes that have been read from serial
+ and are waiting to be dealt with by the user.
+
+
+
+
+
+
+
+
+
+
+
+clear
+
+public void clear()
+
+
Ignore all the bytes read so far and empty the buffer.
+
+
+
+
+
+
+
+
+
+
+
+read
+
+public int read()
+
+
Returns a number between 0 and 255 for the next byte that's
+ waiting in the buffer.
+ Returns -1 if there was no byte (although the user should
+ first check available() to see if things are ready to avoid this)
+
+
+
+
+
+
+
+
+
+
+
+readChar
+
+public char readChar()
+
+
Returns the next byte in the buffer as a char.
+ Returns -1, or 0xffff, if nothing is there.
+
+
+
+
+
+
+
+
+
+
+
+readBytes
+
+public byte[] readBytes()
+
+
Return a byte array of anything that's in the serial buffer.
+ Not particularly memory/speed efficient, because it creates
+ a byte array on each read, but it's easier to use than
+ readBytes(byte b[]) (see below).
+
+
+
+
+
+
+
+
+
+
+
+readBytes
+
+public int readBytes(byte[] outgoing)
+
+
Grab whatever is in the serial buffer, and stuff it into a
+ byte buffer passed in by the user. This is more memory/time
+ efficient than readBytes() returning a byte[] array.
+
+ Returns an int for how many bytes were read. If more bytes
+ are available than can fit into the byte array, only those
+ that will fit are read.
+
+
+
+
+
+
+
+
+
+
+
+readBytesUntil
+
+public byte[] readBytesUntil(int interesting)
+
+
Reads from the serial port into a buffer of bytes up to and
+ including a particular character. If the character isn't in
+ the serial buffer, then 'null' is returned.
+
+
+
+
+
+
+
+
+
+
+
+readBytesUntil
+
+public int readBytesUntil(int interesting,
+ byte[] outgoing)
+
+
Reads from the serial port into a buffer of bytes until a
+ particular character. If the character isn't in the serial
+ buffer, then 'null' is returned.
+
+ If outgoing[] is not big enough, then -1 is returned,
+ and an error message is printed on the console.
+ If nothing is in the buffer, zero is returned.
+ If 'interesting' byte is not in the buffer, then 0 is returned.
+
+
+
+
+
+
+
+
+
+
+
+readString
+
+public java.lang.String readString()
+
+
Return whatever has been read from the serial port so far
+ as a String. It assumes that the incoming characters are ASCII.
+
+ If you want to move Unicode data, you can first convert the
+ String to a byte stream in the representation of your choice
+ (i.e. UTF8 or two-byte Unicode data), and send it as a byte array.
+
Combination of readBytesUntil and readString. See caveats in
+ each function. Returns null if it still hasn't found what
+ you're looking for.
+
+ If you want to move Unicode data, you can first convert the
+ String to a byte stream in the representation of your choice
+ (i.e. UTF8 or two-byte Unicode data), and send it as a byte array.
+
+
+
+
+
+
+
+
+
+
+
+write
+
+public void write(int what)
+
+
This will handle ints, bytes and chars transparently.
+
+
+
+
+
+
+
+
+
+
+
+write
+
+public void write(byte[] bytes)
+
+
+
+
+
+
+
+
+
+
+
+write
+
+public void write(java.lang.String what)
+
+
Write a String to the output. Note that this doesn't account
+ for Unicode (two bytes per char), nor will it send UTF8
+ characters.. It assumes that you mean to send a byte buffer
+ (most often the case for networking and serial i/o) and
+ will only use the bottom 8 bits of each char in the string.
+ (Meaning that internally it uses String.getBytes)
+
+ If you want to move Unicode data, you can first convert the
+ String to a byte stream in the representation of your choice
+ (i.e. UTF8 or two-byte Unicode data), and send it as a byte array.
+
Returns the next client in line that has something to say.
+
+
+
+
+
+
+
+
+
+
+
+stop
+
+public void stop()
+
+
Disconnect all clients and stop the server.
+
+ Use this to shut down the server if you finish using it while your applet
+ is still running. Otherwise, it will be automatically be shut down by the
+ host PApplet using dispose(), which is identical.
+
+
+
+
+
+
+
+
+
+
+
+dispose
+
+public void dispose()
+
+
Disconnect all clients and stop the server: internal use only.
+
+
+
+
+
+
+
+
+
+
+
+run
+
+public void run()
+
+
+
Specified by:
run in interface java.lang.Runnable
+
+
+
+
+
+
+
+
+write
+
+public void write(int what)
+
+
Write a value to all the connected clients.
+ See Client.write() for operational details.
+
+
+
+
+
+
+
+
+
+
+
+write
+
+public void write(byte[] what)
+
+
Write a byte array to all the connected clients.
+ See Client.write() for operational details.
+
+
+
+
+
+
+
+
+
+
+
+write
+
+public void write(java.lang.String what)
+
+
Write a String to all the connected clients.
+ See Client.write() for operational details.
+
+There must be a better way to do this, but I'm having a brain fart
+ with all the inner class crap. Fix it later once this stuff is debugged.
+
+ The method "void vertex(float $1, float $2, float $3);" contained in
+ the enclosing type "processing.core.PGraphics3" is a perfect match for
+ this method call. However, it is not visible in this nested class because
+ a method with the same name in an intervening class is hiding it.
+
Implementation of the GLU_TESS_COMBINE callback.
+
+
+
Specified by:
combine in interface javax.media.opengl.glu.GLUtessellatorCallback
Overrides:
combine in class javax.media.opengl.glu.GLUtessellatorCallbackAdapter
+
+
+
Parameters:
coords - is the 3-vector of the new vertex
data - is the vertex data to be combined, up to four elements.
+ This is useful when mixing colors together or any other
+ user data that was passed in to gluTessVertex.
weight - is an array of weights, one for each element of "data"
+ that should be linearly combined for new values.
outData - is the set of new values of "data" after being
+ put back together based on the weights. it's passed back as a
+ single element Object[] array because that's the closest
+ that Java gets to a pointer.
+Implementation of the PGraphics API that employs OpenGL rendering via JOGL.
+
+ JOGL requires Java 1.4 or higher, so there are no restrictions on this
+ code to be compatible with Java 1.1 or Java 1.3.
+
+ This code relies on PGraphics3D for all lighting and transformations.
+ Meaning that translate(), rotate(), and any lighting will be done in
+ PGraphics3D, and OpenGL is only used to blit lines and triangles as fast
+ as it possibly can.
+
+ For this reason, OpenGL may not be accelerated as far as it could be,
+ but I don't have the time to maintain two separate versions of the
+ renderer. My development time must always be focused on implementation
+ and covering features first, and optimizing later.
+
+ Further, the difference may be negligible, as the primary slowdown
+ in Java is moving pixels (i.e. a large frame buffer is nearly impossible
+ because Java just can't do a MemoryImageSource at screen resolution)
+ and the overhead from JNI tends to be significant. In the latter case,
+ we may even save time in some cases where a large number of calls to
+ OpenGL would otherwise be used, but that's probably a stretch.
+
+ The code is also very messy, while features are being added and
+ removed rapidly as we head towards 1.0. Things got particularly ugly
+ as we approached beta while both Simon and I were working on it.
+ Relax, we'll get it fixed up later.
+
+ When exporting applets, the JOGL Applet Launcher is used. More information
+ about the launcher can be found at its documentation page.
+
+
+
+
+
+
+
+
+
+
+
+
+Nested Class Summary
+
+
+
+ class
+
PGraphicsOpenGL.TessCallback
+
+
+ There must be a better way to do this, but I'm having a brain fart
+ with all the inner class crap.
+
+
+
+
+
+
+
+
+Field Summary
+
+
+
+static boolean
+
BIG_ENDIAN
+
+
+ Set to true if the host system is big endian (PowerPC, MIPS, SPARC),
+ false if little endian (x86 Intel for Mac or PC).
canDraw()
+
+
+ OpenGL cannot draw until a proper native peer is available, so this
+ returns the value of PApplet.isDisplayable() (inherited from Component).
See notes in PGraphics.
+ If z-sorting has been turned on, then the triangles will
+ all be quicksorted here (to make alpha work more properly)
+ and then blit to the screen.
+
+ For the most part, hints are temporary api quirks,
+ for which a proper api hasn't been properly worked out.
+ for instance SMOOTH_IMAGES existed because smooth()
+ wasn't yet implemented, but it will soon go away.
+
+ They also exist for obscure features in the graphics
+ engine, like enabling/disabling single pixel lines
+ that ignore the zbuffer, the way they do in alphabot.
+
+ Current hint options:
+
+
DISABLE_DEPTH_TEST -
+ turns off the z-buffer in the P3D or OPENGL renderers.
+
Returns the ascent of the current font at the current size.
+ This is a method, rather than a variable inside the PGraphics object
+ because it requires calculation.
+
Returns the descent of the current font at the current size.
+ This is a method, rather than a variable inside the PGraphics object
+ because it requires calculation.
+
Sets the current font. The font's size will be the "natural"
+ size of this font (the size that was set when using "Create Font").
+ The leading will also be reset.
+
Add an ambient light based on the current color mode.
+ This version includes an (x, y, z) position for situations
+ where the falloff distance is used.
+
Call this when you want to mess with the pixels[] array.
+
+ For subclasses where the pixels[] buffer isn't set by default,
+ this should copy all data into the pixels[] array
+
Returns an ARGB "color" type (a packed 32 bit int with the color.
+ If the coordinate is outside the image, zero is returned
+ (black, but completely transparent).
+
+ If the image is in RGB format (i.e. on a PVideo object),
+ the value will get its high bits set, just to avoid cases where
+ they haven't been set already.
+
+ If the image is in ALPHA format, this returns a white with its
+ alpha value set.
+
+ This function is included primarily for beginners. It is quite
+ slow because it has to check to see if the x, y that was provided
+ is inside the bounds, and then has to check to see what image
+ type it is. If you want things to be more efficient, access the
+ pixels[] array directly.
+
+ TODO not optimized properly, creates multiple temporary buffers
+ the size of the image. Needs to instead use image cache, but that
+ requires two types of image cache. One for power of 2 textures
+ and another for glReadPixels/glDrawPixels data that's flipped
+ vertically. Both have their components all swapped to native.
+
Set alpha channel for an image. Black colors in the source
+ image will make the destination image completely transparent,
+ and white will make things fully opaque. Gray values will
+ be in-between steps.
+
+ Strictly speaking the "blue" value from the source image is
+ used as the alpha color. For a fully grayscale image, this
+ is correct, but for a color image it's not 100% accurate.
+ For a more accurate conversion, first use filter(GRAY)
+ which will make the image into a "correct" grayscake by
+ performing a proper luminance-based conversion.
+
This is really inefficient and not a good idea in OpenGL.
+ Use get() and set() with a smaller image area, or call the
+ filter on an image instead, and then draw that.
+
This is really inefficient and not a good idea in OpenGL.
+ Use get() and set() with a smaller image area, or call the
+ filter on an image instead, and then draw that.
+
addFonts(java.lang.String directory)
+
+
+ Add a directory that should be searched for font data.
+
+
+
+ void
+
beginDraw()
+
+
+ Prepares the PGraphics for drawing.
+
+
+
+ void
+
blend(int sx,
+ int sy,
+ int dx,
+ int dy,
+ int mode)
+
+
+
+
+
+
+ void
+
blend(int sx1,
+ int sy1,
+ int sx2,
+ int sy2,
+ int dx1,
+ int dy1,
+ int dx2,
+ int dy2,
+ int mode)
+
+
+ Blends one area of this image to another area.
+
+
+
+ void
+
blend(PImage src,
+ int sx,
+ int sy,
+ int dx,
+ int dy,
+ int mode)
+
+
+
+
+
+
+ void
+
blend(PImage src,
+ int sx1,
+ int sy1,
+ int sx2,
+ int sy2,
+ int dx1,
+ int dy1,
+ int dx2,
+ int dy2,
+ int mode)
+
+
+ Copies area of one image into another PImage object.
+
+
+
+ void
+
copy(int sx1,
+ int sy1,
+ int sx2,
+ int sy2,
+ int dx1,
+ int dy1,
+ int dx2,
+ int dy2)
+
+
+ Copy things from one area of this image
+ to another area in the same image.
+
+
+
+ void
+
copy(PImage src,
+ int sx1,
+ int sy1,
+ int sx2,
+ int sy2,
+ int dx1,
+ int dy1,
+ int dx2,
+ int dy2)
+
+
+ Copies area of one image into another PImage object.
+
+
+
+ boolean
+
displayable()
+
+
+ Don't open a window for this renderer, it won't be used.
+
+
+
+ void
+
dispose()
+
+
+ Handle any takedown for this graphics context.
+
+
+
+ void
+
endDraw()
+
+
+ This will finalize rendering so that it can be shown on-screen.
+
+
+
+ void
+
filter(int kind)
+
+
+ Method to apply a variety of basic filters to this image.
+
+
+
+ void
+
filter(int kind,
+ float param)
+
+
+ Method to apply a variety of basic filters to this image.
This will finalize rendering so that it can be shown on-screen.
+
+ When creating your own PGraphics, you should call this when
+ you're finished drawing.
+
Change the textMode() to either SHAPE or MODEL.
+
+ This resets all renderer settings, and should therefore
+ be called before any other commands that set the fill()
+ or the textFont() or anything. Unlike other renderers,
+ use textMode() directly after the size() command.
+
+ This is called when a sketch is shut down and this renderer was
+ specified using the size() command, or inside endRecord() and
+ endRaw(), in order to shut things off.
+
Call this when you want to mess with the pixels[] array.
+
+ For subclasses where the pixels[] buffer isn't set by default,
+ this should copy all data into the pixels[] array
+
Returns an ARGB "color" type (a packed 32 bit int with the color.
+ If the coordinate is outside the image, zero is returned
+ (black, but completely transparent).
+
+ If the image is in RGB format (i.e. on a PVideo object),
+ the value will get its high bits set, just to avoid cases where
+ they haven't been set already.
+
+ If the image is in ALPHA format, this returns a white with its
+ alpha value set.
+
+ This function is included primarily for beginners. It is quite
+ slow because it has to check to see if the x, y that was provided
+ is inside the bounds, and then has to check to see what image
+ type it is. If you want things to be more efficient, access the
+ pixels[] array directly.
+
Efficient method of drawing an image's pixels directly to this surface.
+ No variations are employed, meaning that any scale, tint, or imageMode
+ settings will be ignored.
+
Set alpha channel for an image. Black colors in the source
+ image will make the destination image completely transparent,
+ and white will make things fully opaque. Gray values will
+ be in-between steps.
+
+ Strictly speaking the "blue" value from the source image is
+ used as the alpha color. For a fully grayscale image, this
+ is correct, but for a color image it's not 100% accurate.
+ For a more accurate conversion, first use filter(GRAY)
+ which will make the image into a "correct" grayscake by
+ performing a proper luminance-based conversion.
+
+ As of revision 0100, this function requires an absolute path,
+ in order to avoid confusion. To save inside the sketch folder,
+ use the function savePath() from PApplet, or use saveFrame() instead.
+ As of revision 0116, savePath() is not needed if this object has been
+ created (as recommended) via createImage() or createGraphics() or
+ one of its neighbors.
+
+ As of revision 0115, when using Java 1.4 and later, you can write
+ to several formats besides tga and tiff. If Java 1.4 is installed
+ and the extension used is supported (usually png, jpg, jpeg, bmp,
+ and tiff), then those methods will be used to write the image.
+ To get a list of the supported formats for writing, use:
+ println(javax.imageio.ImageIO.getReaderFormatNames())
+
+ To use the original built-in image writers, use .tga or .tif as the
+ extension, or don't include an extension. When no extension is used,
+ the extension .tif will be added to the file name.
+
+ The ImageIO API claims to support wbmp files, however they probably
+ require a black and white image. Basic testing produced a zero-length
+ file with no error.
+
Add a directory that should be searched for font data.
+
+ On Mac OS X, the following directories are added by default:
+
+
/System/Library/Fonts
+
/Library/Fonts
+
~/Library/Fonts
+
+ On Windows, all drive letters are searched for WINDOWS\Fonts
+ or WINNT\Fonts, any that exists is added.
+
+ On Linux or any other platform, you'll need to add the
+ directories by hand. (If there are actual standards here that we
+ can use as a starting point, please file a bug to make a note of it)
+
+
+
+
+
+
+
+
+listFonts
+
+public java.lang.String[] listFonts()
+
+
List the fonts known to the PDF renderer. This is like PFont.list(),
+ however not all those fonts are available by default.
+
Serial(PApplet parent,
+ java.lang.String iname,
+ int irate,
+ char iparity,
+ int idatabits,
+ float istopbits)
+
+
+
+
+
+
+
+
+
+
+
+
+Method Summary
+
+
+
+ int
+
available()
+
+
+ Returns the number of bytes that have been read from serial
+ and are waiting to be dealt with by the user.
+
+
+
+ void
+
buffer(int count)
+
+
+ Set number of bytes to buffer before calling serialEvent()
+ in the host applet.
+
+
+
+ void
+
bufferUntil(int what)
+
+
+ Set a specific byte to buffer until before calling
+ serialEvent() in the host applet.
+
+
+
+ void
+
clear()
+
+
+ Ignore all the bytes read so far and empty the buffer.
+
+
+
+ void
+
dispose()
+
+
+ Used by PApplet to shut things down.
+
+
+
+static void
+
errorMessage(java.lang.String where,
+ java.lang.Throwable e)
+
+
+ General error reporting, all corraled here just in case
+ I think of something slightly more intelligent to do.
+
+
+
+ int
+
last()
+
+
+ Same as read() but returns the very last value received
+ and clears the buffer.
+ Basically just a user-accessible version of dispose().
+ For now, it just calls dispose(), but dispose shouldn't
+ be called from applets, because in some libraries,
+ dispose() blows shit up if it's called by a user who
+ doesn't know what they're doing.
+
serialEvent in interface gnu.io.SerialPortEventListener
+
+
+
+
+
+
+
+
+buffer
+
+public void buffer(int count)
+
+
Set number of bytes to buffer before calling serialEvent()
+ in the host applet.
+
+
+
+
+
+
+
+
+
+
+
+bufferUntil
+
+public void bufferUntil(int what)
+
+
Set a specific byte to buffer until before calling
+ serialEvent() in the host applet.
+
+
+
+
+
+
+
+
+
+
+
+available
+
+public int available()
+
+
Returns the number of bytes that have been read from serial
+ and are waiting to be dealt with by the user.
+
+
+
+
+
+
+
+
+
+
+
+clear
+
+public void clear()
+
+
Ignore all the bytes read so far and empty the buffer.
+
+
+
+
+
+
+
+
+
+
+
+read
+
+public int read()
+
+
Returns a number between 0 and 255 for the next byte that's
+ waiting in the buffer.
+ Returns -1 if there was no byte (although the user should
+ first check available() to see if things are ready to avoid this)
+
+
+
+
+
+
+
+
+
+
+
+last
+
+public int last()
+
+
Same as read() but returns the very last value received
+ and clears the buffer. Useful when you just want the most
+ recent value sent over the port.
+
+
+
+
+
+
+
+
+
+
+
+readChar
+
+public char readChar()
+
+
Returns the next byte in the buffer as a char.
+ Returns -1, or 0xffff, if nothing is there.
+
+
+
+
+
+
+
+
+
+
+
+lastChar
+
+public char lastChar()
+
+
Just like last() and readChar().
+
+
+
+
+
+
+
+
+
+
+
+readBytes
+
+public byte[] readBytes()
+
+
Return a byte array of anything that's in the serial buffer.
+ Not particularly memory/speed efficient, because it creates
+ a byte array on each read, but it's easier to use than
+ readBytes(byte b[]) (see below).
+
+
+
+
+
+
+
+
+
+
+
+readBytes
+
+public int readBytes(byte[] outgoing)
+
+
Grab whatever is in the serial buffer, and stuff it into a
+ byte buffer passed in by the user. This is more memory/time
+ efficient than readBytes() returning a byte[] array.
+
+ Returns an int for how many bytes were read. If more bytes
+ are available than can fit into the byte array, only those
+ that will fit are read.
+
+
+
+
+
+
+
+
+
+
+
+readBytesUntil
+
+public byte[] readBytesUntil(int interesting)
+
+
Reads from the serial port into a buffer of bytes up to and
+ including a particular character. If the character isn't in
+ the serial buffer, then 'null' is returned.
+
+
+
+
+
+
+
+
+
+
+
+readBytesUntil
+
+public int readBytesUntil(int interesting,
+ byte[] outgoing)
+
+
Reads from the serial port into a buffer of bytes until a
+ particular character. If the character isn't in the serial
+ buffer, then 'null' is returned.
+
+ If outgoing[] is not big enough, then -1 is returned,
+ and an error message is printed on the console.
+ If nothing is in the buffer, zero is returned.
+ If 'interesting' byte is not in the buffer, then 0 is returned.
+
+
+
+
+
+
+
+
+
+
+
+readString
+
+public java.lang.String readString()
+
+
Return whatever has been read from the serial port so far
+ as a String. It assumes that the incoming characters are ASCII.
+
+ If you want to move Unicode data, you can first convert the
+ String to a byte stream in the representation of your choice
+ (i.e. UTF8 or two-byte Unicode data), and send it as a byte array.
+
Combination of readBytesUntil and readString. See caveats in
+ each function. Returns null if it still hasn't found what
+ you're looking for.
+
+ If you want to move Unicode data, you can first convert the
+ String to a byte stream in the representation of your choice
+ (i.e. UTF8 or two-byte Unicode data), and send it as a byte array.
+
+
+
+
+
+
+
+
+
+
+
+write
+
+public void write(int what)
+
+
This will handle both ints, bytes and chars transparently.
+
+
+
+
+
+
+
+
+
+
+
+write
+
+public void write(byte[] bytes)
+
+
+
+
+
+
+
+
+
+
+
+write
+
+public void write(java.lang.String what)
+
+
Write a String to the output. Note that this doesn't account
+ for Unicode (two bytes per char), nor will it send UTF8
+ characters.. It assumes that you mean to send a byte buffer
+ (most often the case for networking and serial i/o) and
+ will only use the bottom 8 bits of each char in the string.
+ (Meaning that internally it uses String.getBytes)
+
+ If you want to move Unicode data, you can first convert the
+ String to a byte stream in the representation of your choice
+ (i.e. UTF8 or two-byte Unicode data), and send it as a byte array.
+
+
+
+
+
+
+
+
+
+
+
+list
+
+public static java.lang.String[] list()
+
+
If this just hangs and never completes on Windows,
+ it may be because the DLL doesn't have its exec bit set.
+ Why the hell that'd be the case, who knows.
+
Capture(PApplet parent,
+ int requestWidth,
+ int requestHeight)
+
+
+
+
+
+
Capture(PApplet parent,
+ int reqWidth,
+ int reqHeight,
+ int frameRate)
+
+
+
+
+
+
Capture(PApplet parent,
+ int reqWidth,
+ int reqHeight,
+ java.lang.String name)
+
+
+
+
+
+
Capture(PApplet parent,
+ int requestWidth,
+ int requestHeight,
+ java.lang.String name,
+ int frameRate)
+
+
+ If 'name' is null or the empty string, it won't set a specific
+ device, which means that QuickTime will use that last device
+ used by a QuickTime application.
+
+
+
+
+
+
+
+
+
+Method Summary
+
+
+
+ boolean
+
available()
+
+
+ True if a frame is ready to be read.
+
+
+
+ void
+
crop(int x,
+ int y,
+ int w,
+ int h)
+
+
+ Set the video to crop from its original.
+
+
+
+ void
+
dispose()
+
+
+ Called by PApplet to shut down video so that QuickTime
+ can be used later by another applet.
+
+
+
+ void
+
format(int which)
+
+
+ Set the video format standard to use on the
+ video digitizer: NTSC, PAL, or SECAM.
+
+
+
+ void
+
frameRate(int iframeRate)
+
+
+ Set the frameRate for how quickly new frames are read
+ from the capture device.
+
+
+
+ void
+
init(PApplet parent,
+ int requestWidth,
+ int requestHeight,
+ java.lang.String name,
+ int frameRate)
+
+
+
+
+
+
+static java.lang.String[]
+
list()
+
+
+ Get a list of all available captures as a String array.
+
+
+
+ void
+
noCrop()
+
+
+ Remove the cropping (if any) of the image.
Temporary storage for the raw image
+ data read directly from the capture device
+
+
+
+
+
+
+
+dataWidth
+
+public int dataWidth
+
+
+
+
+
+
+
+dataHeight
+
+public int dataHeight
+
+
+
+
+
+
+
+dataRowBytes
+
+public int dataRowBytes
+
+
+
+
+
+
+
+crop
+
+public boolean crop
+
+
True if this image is currently being cropped
+
+
+
+
+
+
+
+cropX
+
+public int cropX
+
+
+
+
+
+
+
+cropY
+
+public int cropY
+
+
+
+
+
+
+
+cropW
+
+public int cropW
+
+
+
+
+
+
+
+cropH
+
+public int cropH
+
+
+
+
+
+
+
+frameRate
+
+public int frameRate
+
+
+
+
+
+
+
+raw
+
+public quicktime.util.RawEncodedImage raw
+
+
+
+
+
+
+
+capture
+
+public quicktime.std.sg.SequenceGrabber capture
+
+
+
+
+
+
+
+channel
+
+public quicktime.std.sg.SGVideoChannel channel
+
+
the guy who's doing all the work
+
+
+
+
+
+
+
+
+
+
+
+Constructor Detail
+
+
+
+
+Capture
+
+public Capture(PApplet parent,
+ int requestWidth,
+ int requestHeight)
+
+
+
+
+
+Capture
+
+public Capture(PApplet parent,
+ int reqWidth,
+ int reqHeight,
+ int frameRate)
+
+
+
+
+
+Capture
+
+public Capture(PApplet parent,
+ int reqWidth,
+ int reqHeight,
+ java.lang.String name)
+
+
+
+
+
+Capture
+
+public Capture(PApplet parent,
+ int requestWidth,
+ int requestHeight,
+ java.lang.String name,
+ int frameRate)
+
+
If 'name' is null or the empty string, it won't set a specific
+ device, which means that QuickTime will use that last device
+ used by a QuickTime application.
+
+ Unfortunately, Apple's QuickTime API uses the name to select devices,
+ and in some cases there might be cameras with the same name on a machine.
+ If you ask for a camera of the same name in sequence, you might see if it
+ just does the right thing and grabs each separate camera in succession.
+ If that doesn't work, you might try calling settings() which will
+ bring up the prompt where you can select a capture device.
+
+ If the following function:
+
public void captureEvent(Capture c)
+ is defined in the host PApplet, then it will be called every
+ time a new frame is available from the capture device.
+
+
+
+
+
+
+
+
+
+Method Detail
+
+
+
+
+init
+
+public void init(PApplet parent,
+ int requestWidth,
+ int requestHeight,
+ java.lang.String name,
+ int frameRate)
+
+
+
+
+
+
+
+
+
+
+
+available
+
+public boolean available()
+
+
True if a frame is ready to be read.
+
+ // put this somewhere inside draw
+ if (capture.available()) capture.read();
+
+ Alternatively, you can use captureEvent(Capture c) to notify you
+ whenever available() is set to true. In which case, things might
+ look like this:
+
+ public void captureEvent(Capture c) {
+ c.read();
+ // do something exciting now that c has been updated
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+crop
+
+public void crop(int x,
+ int y,
+ int w,
+ int h)
+
+
Set the video to crop from its original.
+
+ It seems common that captures add lines to the top or bottom
+ of an image, so this can be useful for removing them.
+ Internally, the pixel buffer size returned from QuickTime is
+ often a different size than requested, so crop will be set
+ more often than not.
+
+
+
+
+
+
+
+
+
+
+
+noCrop
+
+public void noCrop()
+
+
Remove the cropping (if any) of the image.
+
+ By default, cropping is often enabled to trim out black pixels.
+ But if you'd rather deal with them yourself (so as to avoid
+ an extra lag while the data is moved around) you can shut it off.
+
+
+
+
+
+
+
+
+
+
+
+read
+
+public void read()
+
+
+
+
+
+
+
+
+
+
+
+run
+
+public void run()
+
+
+
Specified by:
run in interface java.lang.Runnable
+
+
+
+
+
+
+
+
+frameRate
+
+public void frameRate(int iframeRate)
+
+
Set the frameRate for how quickly new frames are read
+ from the capture device.
+
+
+
+
+
+
+
+
+
+
+
+stop
+
+public void stop()
+
+
Called by applets to stop capturing video.
+
+
+
+
+
+
+
+
+
+
+
+dispose
+
+public void dispose()
+
+
Called by PApplet to shut down video so that QuickTime
+ can be used later by another applet.
+
+
+
+
+
+
+
+
+
+
+
+source
+
+public void source(int which)
+
+
Set the format to ask for from the video digitizer:
+ TUNER, COMPOSITE, SVIDEO, or COMPONENT.
+
+ The constants are just aliases to the constants returned from
+ QuickTime's getInputFormat() function, so any valid constant from
+ that will work just fine.
+
+
+
+
+
+
+
+
+
+
+
+format
+
+public void format(int which)
+
+
Set the video format standard to use on the
+ video digitizer: NTSC, PAL, or SECAM.
+
+ The constants are just aliases to the constants used for
+ QuickTime's setInputStandard() function, so any valid
+ constant from that will work just fine.
+
+
+
+
+
+
+
+
+
+
+
+settings
+
+public void settings()
+
+
Show the settings dialog for this input device.
+
+
+
+
+
+
+
+
+
+
+
+list
+
+public static java.lang.String[] list()
+
+
Get a list of all available captures as a String array.
+ i.e. println(Capture.list()) will show you the goodies.
+
+public Movie(PApplet parent,
+ java.lang.String filename,
+ int ifps)
+
+
+
+
+
+
+
+
+
+Method Detail
+
+
+
+
+init
+
+public void init(PApplet parent,
+ java.lang.String filename,
+ int fps)
+
+
+
+
+
+
+
+
+
+
+
+available
+
+public boolean available()
+
+
+
+
+
+
+
+
+
+
+
+read
+
+public void read()
+
+
+
+
+
+
+
+
+
+
+
+play
+
+public void play()
+
+
Begin playing the movie, with no repeat.
+
+
+
+
+
+
+
+
+
+
+
+loop
+
+public void loop()
+
+
Begin playing the movie, with repeat.
+
+
+
+
+
+
+
+
+
+
+
+noLoop
+
+public void noLoop()
+
+
Shut off the repeating loop.
+
+
+
+
+
+
+
+
+
+
+
+pause
+
+public void pause()
+
+
Pause the movie at its current time.
+
+
+
+
+
+
+
+
+
+
+
+stop
+
+public void stop()
+
+
Stop the movie, and rewind.
+
+
+
+
+
+
+
+
+
+
+
+frameRate
+
+public void frameRate(int ifps)
+
+
Set how often new frames are to be read from the movie.
+ Does not actually set the speed of the movie playback,
+ that's handled by the speed() method.
+
+
+
+
+
+
+
+
+
+
+
+speed
+
+public void speed(float rate)
+
+
Set a multiplier for how fast/slow the movie should be run.
+ The default is 1.0.
+
+
speed(2) will play the movie at double speed (2x).
+
speed(0.5) will play at half speed.
+
speed(-1) will play backwards at regular speed.
+
+
+
+
+
+
+
+
+
+
+
+
+time
+
+public float time()
+
+
Return the current time in seconds.
+ The number is a float so fractions of seconds can be used.
+
+
+
+
+
+
+
+
+
+
+
+jump
+
+public void jump(float where)
+
+
Jump to a specific location (in seconds).
+ The number is a float so fractions of seconds can be used.
+
+
+
+
+
+
+
+
+
+
+
+duration
+
+public float duration()
+
+
Get the full length of this movie (in seconds).
+
+
+
+
+
+
+
+
+
+
+
+run
+
+public void run()
+
+
+
Specified by:
run in interface java.lang.Runnable
+
+
+
+
+
+
+
+
+dispose
+
+public void dispose()
+
+
Call this to halt the movie from running, and stop its thread.
+
MovieMaker(PApplet p,
+ int _w,
+ int _h,
+ java.lang.String _filename)
+
+
+ Create a movie with the specified width, height, and filename.
+
+
+
MovieMaker(PApplet p,
+ int _w,
+ int _h,
+ java.lang.String _filename,
+ int _rate)
+
+
+ Create a movie with the specified width, height, filename, and frame rate.
+
+
+
MovieMaker(PApplet p,
+ int _w,
+ int _h,
+ java.lang.String _filename,
+ int _rate,
+ int _codecType,
+ int _codecQuality)
+
+
+ Create a movie with the specified width, height, filename, frame rate,
+ and codec type and quality.
+
+
+
MovieMaker(PApplet p,
+ int _w,
+ int _h,
+ java.lang.String _filename,
+ int _rate,
+ int _codecType,
+ int _codecQuality,
+ int _keyFrameRate)
+
+
+ Create a movie with the specified width, height, filename, frame rate,
+ codec type and quality, and key frame rate.
+public MovieMaker(PApplet p,
+ int _w,
+ int _h,
+ java.lang.String _filename)
+
+
Create a movie with the specified width, height, and filename.
+ The movie will be created at 15 frames per second.
+ The codec will be set to RAW and quality set to HIGH.
+
+
+
+
+
+MovieMaker
+
+public MovieMaker(PApplet p,
+ int _w,
+ int _h,
+ java.lang.String _filename,
+ int _rate)
+
+
Create a movie with the specified width, height, filename, and frame rate.
+ The codec will be set to RAW and quality set to HIGH.
+
+
+
+
+
+MovieMaker
+
+public MovieMaker(PApplet p,
+ int _w,
+ int _h,
+ java.lang.String _filename,
+ int _rate,
+ int _codecType,
+ int _codecQuality)
+
+
Create a movie with the specified width, height, filename, frame rate,
+ and codec type and quality. Key frames will be set at 15 frames.
+
+
+
+
+
+MovieMaker
+
+public MovieMaker(PApplet p,
+ int _w,
+ int _h,
+ java.lang.String _filename,
+ int _rate,
+ int _codecType,
+ int _codecQuality,
+ int _keyFrameRate)
+
+
Create a movie with the specified width, height, filename, frame rate,
+ codec type and quality, and key frame rate.
+
+
+
+
+
+
+
+
+
+Method Detail
+
+
+
+
+addFrame
+
+public void addFrame()
+
+
+
+
+
+
+
+
+addFrame
+
+public void addFrame(int[] _pixels,
+ int w,
+ int h)
addAttribute(java.lang.String key,
+ java.lang.String nsPrefix,
+ java.lang.String nsURI,
+ java.lang.String value,
+ java.lang.String type)
+
+
+ This method is called when a new attribute of an XML element is
+ encountered.
+
+
+
+ void
+
addPCData(java.io.Reader reader,
+ java.lang.String systemID,
+ int lineNr)
+
+
+ This method is called when a PCDATA element is encountered.
+
+
+
+ void
+
elementAttributesProcessed(java.lang.String name,
+ java.lang.String nsPrefix,
+ java.lang.String nsURI)
+
+
+ This method is called when the attributes of an XML element have been
+ processed.
+
+
+
+ void
+
endElement(java.lang.String name,
+ java.lang.String nsPrefix,
+ java.lang.String nsURI)
+
+
+ This method is called when the end of an XML elemnt is encountered.
+
+
+
+ java.lang.Object
+
getResult()
+
+
+ Returns the result of the building process.
+
+
+
+ void
+
newProcessingInstruction(java.lang.String target,
+ java.io.Reader reader)
+
+
+ This method is called when a processing instruction is encountered.
+
+
+
+ void
+
startBuilding(java.lang.String systemID,
+ int lineNr)
+
+
+ This method is called before the parser starts processing its input.
+
+
+
+ void
+
startElement(java.lang.String name,
+ java.lang.String nsPrefix,
+ java.lang.String nsURI,
+ java.lang.String systemID,
+ int lineNr)
+
+
+ This method is called when a new XML element is encountered.
This method is called when a new attribute of an XML element is
+ encountered.
+
+
+
Parameters:
key - the key (name) of the attribute.
nsPrefix - the prefix used to identify the namespace. If no
+ namespace has been specified, this parameter is null.
nsURI - the URI associated with the namespace. If no
+ namespace has been specified, or no URI is
+ associated with nsPrefix, this parameter is null.
value - the value of the attribute.
type - the type of the attribute. If no type is known,
+ "CDATA" is returned.
+
Throws:
+
java.lang.Exception - If an exception occurred while processing the event.
+
+
+
+
+
+addPCData
+
+public void addPCData(java.io.Reader reader,
+ java.lang.String systemID,
+ int lineNr)
+
+
This method is called when a PCDATA element is encountered. A Java
+ reader is supplied from which you can read the data. The reader will
+ only read the data of the element. You don't need to check for
+ boundaries. If you don't read the full element, the rest of the data
+ is skipped. You also don't have to care about entities; they are
+ resolved by the parser.
+
+
+
Parameters:
reader - the Java reader from which you can retrieve the data.
systemID - the system ID of the XML data source.
lineNr - the line in the source where the element starts.
+
+
+
+
+
+getResult
+
+public java.lang.Object getResult()
+
+
Returns the result of the building process. This method is called just
+ before the parse method of StdXMLParser returns.
+
Starts a new stream from a Java reader. The new stream is used
+ temporary to read data from. If that stream is exhausted, control
+ returns to the parent stream.
+
+
+
Parameters:
reader - the non-null reader to read the new data from
Starts a new stream from a Java reader. The new stream is used
+ temporary to read data from. If that stream is exhausted, control
+ returns to the parent stream.
+
+
+
Parameters:
reader - the non-null reader to read the new data from
isInternalEntity - true if the reader is produced by resolving
+ an internal entity
+
+
+
+
+
+getStreamLevel
+
+public int getStreamLevel()
+
+
Returns the current "level" of the stream on the stack of streams.
+
+
+
+
+
+
+
+
+getLineNr
+
+public int getLineNr()
+
+
Returns the line number of the data in the current stream.
+
+XMLElement is an XML element. This is the base class used for the
+ Processing XML library, representing a single node of an XML tree.
+
+ This code is based on a modified version of NanoXML by Marc De Scheemaecker.
+
Begin parsing XML data passed in from a PApplet. This code
+ wraps exception handling, for more advanced exception handling,
+ use the constructor that takes a Reader or InputStream.
+
Return the #PCDATA content of the element. If the element has a
+ combination of #PCDATA content and child elements, the #PCDATA
+ sections can be retrieved as unnamed child objects. In this case,
+ this method returns null.
+
+
+
+
+
+
+
Returns:
the content.
+
+
+
+
+
+setContent
+
+public void setContent(java.lang.String content)
+
+
Sets the #PCDATA content. It is an error to call this method with a
+ non-null value if there are child objects.
+
+XMLValidator implementation based on NonValidator (which implemented
+ IXMLValidator in the original NanoXML).
+ This implementation processes the DTD and handles entity definitions.
+ It does not do any validation itself.
+
attributeAdded(java.lang.String key,
+ java.lang.String value,
+ java.lang.String systemId,
+ int lineNr)
+
+
+ Indicates that an attribute has been added to the current element.
+
+
+
+ void
+
elementAttributesProcessed(java.lang.String name,
+ java.util.Properties extraAttributes,
+ java.lang.String systemId,
+ int lineNr)
+
+
+ This method is called when the attributes of an XML element have been
+ processed.
+
+
+
+ void
+
elementEnded(java.lang.String name,
+ java.lang.String systemId,
+ int lineNr)
+
+
+ Indicates that the current element has ended.
+
+
+
+ void
+
elementStarted(java.lang.String name,
+ java.lang.String systemId,
+ int lineNr)
+
+
+ Indicates that an element has been started.
This method is called when the attributes of an XML element have been
+ processed.
+ If there are attributes with a default value which have not been
+ specified yet, they have to be put into extraAttributes.
+
+
+
Parameters:
name - the name of the element.
extraAttributes - where to put extra attributes.
systemId - the system ID of the XML data of the element.
lineNr - the line number in the XML data of the element.
The PGraphics renderer associated with this PApplet
+
+
+
+
+
+
+frame
+
+java.awt.Frame frame
+
+
The frame containing this applet (if any)
+
+
+
+
+
+
+screen
+
+java.awt.Dimension screen
+
+
The screen size when the applet was started.
+
+ Access this via screen.width and screen.height. To make an applet
+ run at full screen, use size(screen.width, screen.height).
+
+ If you have multiple displays, this will be the size of the main
+ display. Running full screen across multiple displays isn't
+ particularly supported, and requires more monkeying with the values.
+ This probably can't/won't be fixed until/unless I get a dual head
+ system.
+
+ Note that this won't update if you change the resolution
+ of your screen once the the applet is running.
+
+ This variable is not static, because future releases need to be better
+ at handling multiple displays.
+
A leech graphics object that is echoing all events.
+
+
+
+
+
+
+args
+
+java.lang.String[] args
+
+
Command line options passed in from main().
+
+ This does not include the arguments passed in to PApplet itself.
+
+
+
+
+
+
+sketchPath
+
+java.lang.String sketchPath
+
+
Path to sketch folder
+
+
+
+
+
+
+defaultSize
+
+boolean defaultSize
+
+
true if no size() command has been executed. This is used to wait until
+ a size has been set before placing in the window and showing it.
+
+
+
+
+
+
+resizeRequest
+
+boolean resizeRequest
+
+
+
+
+
+
+resizeWidth
+
+int resizeWidth
+
+
+
+
+
+
+resizeHeight
+
+int resizeHeight
+
+
+
+
+
+
+pixels
+
+int[] pixels
+
+
Pixel buffer from this applet's PGraphics.
+
+ When used with OpenGL or Java2D, this value will
+ be null until loadPixels() has been called.
+
+
+
+
+
+
+width
+
+int width
+
+
width of this applet's associated PGraphics
+
+
+
+
+
+
+height
+
+int height
+
+
height of this applet's associated PGraphics
+
+
+
+
+
+
+mouseX
+
+int mouseX
+
+
current x position of the mouse
+
+
+
+
+
+
+mouseY
+
+int mouseY
+
+
current y position of the mouse
+
+
+
+
+
+
+pmouseX
+
+int pmouseX
+
+
Previous x/y position of the mouse. This will be a different value
+ when inside a mouse handler (like the mouseMoved() method) versus
+ when inside draw(). Inside draw(), pmouseX is updated once each
+ frame, but inside mousePressed() and friends, it's updated each time
+ an event comes through. Be sure to use only one or the other type of
+ means for tracking pmouseX and pmouseY within your sketch, otherwise
+ you're gonna run into trouble.
+
+
+
+
+
+
+pmouseY
+
+int pmouseY
+
+
Previous x/y position of the mouse. This will be a different value
+ when inside a mouse handler (like the mouseMoved() method) versus
+ when inside draw(). Inside draw(), pmouseX is updated once each
+ frame, but inside mousePressed() and friends, it's updated each time
+ an event comes through. Be sure to use only one or the other type of
+ means for tracking pmouseX and pmouseY within your sketch, otherwise
+ you're gonna run into trouble.
+
+
+
+
+
+
+dmouseX
+
+int dmouseX
+
+
previous mouseX/Y for the draw loop, separated out because this is
+ separate from the pmouseX/Y when inside the mouse event handlers.
+
+
+
+
+
+
+dmouseY
+
+int dmouseY
+
+
previous mouseX/Y for the draw loop, separated out because this is
+ separate from the pmouseX/Y when inside the mouse event handlers.
+
+
+
+
+
+
+emouseX
+
+int emouseX
+
+
pmouseX/Y for the event handlers (mousePressed(), mouseDragged() etc)
+ these are different because mouse events are queued to the end of
+ draw, so the previous position has to be updated on each event,
+ as opposed to the pmouseX/Y that's used inside draw, which is expected
+ to be updated once per trip through draw().
+
+
+
+
+
+
+emouseY
+
+int emouseY
+
+
pmouseX/Y for the event handlers (mousePressed(), mouseDragged() etc)
+ these are different because mouse events are queued to the end of
+ draw, so the previous position has to be updated on each event,
+ as opposed to the pmouseX/Y that's used inside draw, which is expected
+ to be updated once per trip through draw().
+
+
+
+
+
+
+firstMouse
+
+boolean firstMouse
+
+
Used to set pmouseX/Y to mouseX/Y the first time mouseX/Y are used,
+ otherwise pmouseX/Y are always zero, causing a nasty jump.
+
+ Just using (frameCount == 0) won't work since mouseXxxxx()
+ may not be called until a couple frames into things.
+
+
+
+
+
+
+mouseButton
+
+int mouseButton
+
+
Last mouse button pressed, one of LEFT, CENTER, or RIGHT.
+
+ If running on Mac OS, a ctrl-click will be interpreted as
+ the righthand mouse button (unlike Java, which reports it as
+ the left mouse).
+
+
+
+
+
+
+mousePressed
+
+boolean mousePressed
+
+
+
+
+
+
+mouseEvent
+
+java.awt.event.MouseEvent mouseEvent
+
+
+
+
+
+
+key
+
+char key
+
+
Last key pressed.
+
+ If it's a coded key, i.e. UP/DOWN/CTRL/SHIFT/ALT,
+ this will be set to CODED (0xffff or 65535).
+
+
+
+
+
+
+keyCode
+
+int keyCode
+
+
When "key" is set to CODED, this will contain a Java key code.
+
+ For the arrow keys, keyCode will be one of UP, DOWN, LEFT and RIGHT.
+ Also available are ALT, CONTROL and SHIFT. A full set of constants
+ can be obtained from java.awt.event.KeyEvent, from the VK_XXXX variables.
+
+
+
+
+
+
+keyPressed
+
+boolean keyPressed
+
+
true if the mouse is currently pressed.
+
+
+
+
+
+
+keyEvent
+
+java.awt.event.KeyEvent keyEvent
+
+
the last KeyEvent object passed into a mouse function.
+
+
+
+
+
+
+focused
+
+boolean focused
+
+
Gets set to true/false as the applet gains/loses focus.
+
+
+
+
+
+
+online
+
+boolean online
+
+
true if the applet is online.
+
+ This can be used to test how the applet should behave
+ since online situations are different (no file writing, etc).
+
+
+
+
+
+
+millisOffset
+
+long millisOffset
+
+
Time in milliseconds when the applet was started.
+
+ Used by the millis() function.
+
+
+
+
+
+
+frameRate
+
+float frameRate
+
+
The current value of frames per second.
+
+ The initial value will be 10 fps, and will be updated with each
+ frame thereafter. The value is not instantaneous (since that
+ wouldn't be very useful since it would jump around so much),
+ but is instead averaged (integrated) over several frames.
+ As such, this value won't be valid until after 5-10 frames.
+
+
+
+
+
+
+frameRateLastNanos
+
+long frameRateLastNanos
+
+
Last time in nanoseconds that frameRate was checked
+
+
+
+
+
+
+frameRateTarget
+
+float frameRateTarget
+
+
As of release 0116, frameRate(60) is called as a default
+
+
+
+
+
+
+frameRatePeriod
+
+long frameRatePeriod
+
+
+
+
+
+
+looping
+
+boolean looping
+
+
+
+
+
+
+redraw
+
+boolean redraw
+
+
flag set to true when a redraw is asked for by the user
+
+
+
+
+
+
+frameCount
+
+int frameCount
+
+
How many frames have been displayed since the applet started.
+
+ This value is read-only do not attempt to set it,
+ otherwise bad things will happen.
+
+ Inside setup(), frameCount is 0.
+ For the first iteration of draw(), frameCount will equal 1.
+
+
+
+
+
+
+finished
+
+boolean finished
+
+
true if this applet has had it.
+
+
+
+
+
+
+exitCalled
+
+boolean exitCalled
+
+
true if exit() has been called so that things shut down
+ once the main thread kicks off.
+
By trial and error, four image loading threads seem to work best when
+ loading images from online. This is consistent with the number of open
+ connections that web browsers will maintain. The variable is made public
+ (however no accessor has been added since it's esoteric) if you really
+ want to have control over the value used. For instance, when loading local
+ files, it might be better to only have a single thread (or two) loading
+ images so that you're disk isn't simply jumping around.
+
+
+
diff --git a/build/shared/lib/export/application.exe b/build/shared/lib/export/application.exe
new file mode 100755
index 000000000..ea70a3a2d
Binary files /dev/null and b/build/shared/lib/export/application.exe differ
diff --git a/build/shared/lib/export/loading.gif b/build/shared/lib/export/loading.gif
new file mode 100755
index 000000000..1ddae5089
Binary files /dev/null and b/build/shared/lib/export/loading.gif differ
diff --git a/build/shared/lib/export/skeleton.app/Contents/MacOS/JavaApplicationStub b/build/shared/lib/export/skeleton.app/Contents/MacOS/JavaApplicationStub
new file mode 100755
index 000000000..eeb8b5617
Binary files /dev/null and b/build/shared/lib/export/skeleton.app/Contents/MacOS/JavaApplicationStub differ
diff --git a/build/shared/lib/export/skeleton.app/Contents/PkgInfo b/build/shared/lib/export/skeleton.app/Contents/PkgInfo
new file mode 100755
index 000000000..bd04210fb
--- /dev/null
+++ b/build/shared/lib/export/skeleton.app/Contents/PkgInfo
@@ -0,0 +1 @@
+APPL????
\ No newline at end of file
diff --git a/build/shared/lib/export/skeleton.app/Contents/Resources/sketch.icns b/build/shared/lib/export/skeleton.app/Contents/Resources/sketch.icns
new file mode 100644
index 000000000..8ffb8d7de
Binary files /dev/null and b/build/shared/lib/export/skeleton.app/Contents/Resources/sketch.icns differ
diff --git a/build/shared/lib/export/template.plist b/build/shared/lib/export/template.plist
new file mode 100755
index 000000000..4b56a1170
--- /dev/null
+++ b/build/shared/lib/export/template.plist
@@ -0,0 +1,59 @@
+
+
+
+
+ CFBundleName
+ @@sketch@@
+ CFBundleVersion
+ 10.2
+ CFBundleAllowMixedLocalizations
+ true
+ CFBundleExecutable
+ JavaApplicationStub
+ CFBundleDevelopmentRegion
+ English
+ CFBundlePackageType
+ APPL
+ CFBundleSignature
+ ????
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleIconFile
+ sketch.icns
+ CFBundleIdentifier
+ @@sketch@@
+
+ LSUIPresentationMode
+ @@lsuipresentationmode@@
+ Java
+
+ VMOptions
+ @@vmoptions@@
+ MainClass
+ @@sketch@@
+ JVMVersion
+ 1.5*
+ ClassPath
+ @@classpath@@
+
+ Properties
+
+
+ apple.laf.useScreenMenuBar
+ true
+ apple.awt.showGrowBox
+ false
+ com.apple.smallTabs
+ true
+ apple.awt.Antialiasing
+ false
+ apple.awt.TextAntialiasing
+ true
+ com.apple.hwaccel
+ true
+ apple.awt.use-file-dialog-packages
+ false
+
+
+
+
diff --git a/build/shared/lib/keywords.txt b/build/shared/lib/keywords.txt
new file mode 100644
index 000000000..b2ed52bd0
--- /dev/null
+++ b/build/shared/lib/keywords.txt
@@ -0,0 +1,627 @@
+# LITERAL2 specifies constants
+
+ADD LITERAL2
+ALIGN_CENTER LITERAL2
+ALIGN_LEFT LITERAL2
+ALIGN_RIGHT LITERAL2
+ALPHA LITERAL2
+ALPHA_MASK LITERAL2
+ALT LITERAL2
+AMBIENT LITERAL2
+ARROW LITERAL2
+ARGB LITERAL2
+BACKSPACE LITERAL2
+BASELINE LITERAL2
+BEVEL LITERAL2
+BLEND LITERAL2
+BLUE_MASK LITERAL2
+BLUR LITERAL2
+BOTTOM LITERAL2
+BURN LITERAL2
+CENTER LITERAL2
+CHATTER LITERAL2
+CODED LITERAL2
+COMPLAINT LITERAL2
+COMPOSITE LITERAL2
+COMPONENT LITERAL2
+CONCAVE_POLYGON LITERAL2
+CONTROL LITERAL2
+CONVEX_POLYGON LITERAL2
+CORNER LITERAL2
+CORNERS LITERAL2
+CLOSE LITERAL2
+CMYK LITERAL2
+CODED LITERAL2
+COMPLAINT LITERAL2
+CONTROL LITERAL2
+CORNER LITERAL2
+CORNERS LITERAL2
+CROSS LITERAL2
+CUSTOM LITERAL2
+DARKEST LITERAL2
+DEGREES LITERAL2
+DEG_TO_RAD LITERAL2
+DELETE LITERAL2
+DIAMETER LITERAL2
+DIFFERENCE LITERAL2
+DIFFUSE LITERAL2
+DILATE LITERAL2
+DIRECTIONAL LITERAL2
+DISABLE_ACCURATE_TEXTURES LITERAL2
+DISABLE_DEPTH_SORT LITERAL2
+DISABLE_NATIVE_FONTS LITERAL2
+DISABLE_OPENGL_ERROR_REPORT LITERAL2
+DISABLE_TEXT_SMOOTH LITERAL2
+DISABLED LITERAL2
+DODGE LITERAL2
+DOWN LITERAL2
+DXF LITERAL2
+ENABLE_ACCURATE_TEXTURES LITERAL2
+ENABLE_DEPTH_SORT LITERAL2
+ENABLE_NATIVE_FONTS LITERAL2
+DISABLE_OPENGL_2X_SMOOTH LITERAL2
+ENABLE_OPENGL_4X_SMOOTH LITERAL2
+ENABLE_OPENGL_ERROR_REPORT LITERAL2
+ENTER LITERAL2
+EPSILON LITERAL2
+ERODE LITERAL2
+ESC LITERAL2
+EXCLUSION LITERAL2
+GIF LITERAL2
+GRAY LITERAL2
+GREEN_MASK LITERAL2
+GROUP LITERAL2
+HALF LITERAL2
+HALF_PI LITERAL2
+HAND LITERAL2
+HARD_LIGHT LITERAL2
+HINT_COUNT LITERAL2
+HSB LITERAL2
+IMAGE LITERAL2
+INVERT LITERAL2
+JAVA2D LITERAL2
+JPEG LITERAL2
+LEFT LITERAL2
+LIGHTEST LITERAL2
+LINES LITERAL2
+LINUX LITERAL2
+MACOSX LITERAL2
+MAX_FLOAT LITERAL2
+MAX_INT LITERAL2
+MITER LITERAL2
+MODEL LITERAL2
+MOVE LITERAL2
+MULTIPLY LITERAL2
+NORMAL LITERAL2
+NO_DEPTH_TEST LITERAL2
+NTSC LITERAL2
+ONE LITERAL2
+OPAQUE LITERAL2
+OPEN LITERAL2
+OPENGL LITERAL2
+ORTHOGRAPHIC LITERAL2
+OVERLAY LITERAL2
+PAL LITERAL2
+P2D LITERAL2
+P3D LITERAL2
+PERSPECTIVE LITERAL2
+PI LITERAL2
+PIXEL_CENTER LITERAL2
+POINT LITERAL2
+POINTS LITERAL2
+POSTERIZE LITERAL2
+PROBLEM LITERAL2
+PROJECT LITERAL2
+QUAD_STRIP LITERAL2
+QUADS LITERAL2
+QUARTER_PI LITERAL2
+RAD_TO_DEG LITERAL2
+RADIUS LITERAL2
+RADIANS LITERAL2
+RED_MASK LITERAL2
+REPLACE LITERAL2
+RETURN LITERAL2
+RGB LITERAL2
+RIGHT LITERAL2
+ROUND LITERAL2
+SCREEN LITERAL2
+SECAM LITERAL2
+SHIFT LITERAL2
+SPECULAR LITERAL2
+SOFT_LIGHT LITERAL2
+SQUARE LITERAL2
+SUBTRACT LITERAL2
+SVIDEO LITERAL2
+TAB LITERAL2
+TARGA LITERAL2
+TEXT LITERAL2
+TFF LITERAL2
+THIRD_PI LITERAL2
+THRESHOLD LITERAL2
+TIFF LITERAL2
+TOP LITERAL2
+TRIANGLE_FAN LITERAL2
+TRIANGLES LITERAL2
+TRIANGLE_STRIP LITERAL2
+TUNER LITERAL2
+TWO LITERAL2
+TWO_PI LITERAL2
+UP LITERAL2
+WAIT LITERAL2
+WHITESPACE LITERAL2
+
+
+# KEYWORD1 specifies datatypes and keywords
+
+ArrayList KEYWORD1
+Boolean KEYWORD1
+Byte KEYWORD1
+Character KEYWORD1
+Class KEYWORD1
+Double KEYWORD1
+Float KEYWORD1
+Integer KEYWORD1
+HashMap KEYWORD1
+String KEYWORD1
+StringBuffer KEYWORD1
+Thread KEYWORD1
+abstract KEYWORD1
+assert KEYWORD1
+boolean KEYWORD1
+break KEYWORD1
+byte KEYWORD1
+catch KEYWORD1
+char KEYWORD1
+class KEYWORD1
+continue KEYWORD1
+default KEYWORD1
+do KEYWORD1
+double KEYWORD1
+else KEYWORD1
+enum KEYWORD1
+extends KEYWORD1
+false KEYWORD1
+final KEYWORD1
+finally KEYWORD1
+for KEYWORD1
+float KEYWORD1
+if KEYWORD1
+implements KEYWORD1
+import KEYWORD1
+instanceof KEYWORD1
+int KEYWORD1
+interface KEYWORD1
+long KEYWORD1
+native KEYWORD1
+new KEYWORD1
+null KEYWORD1
+package KEYWORD1
+private KEYWORD1
+protected KEYWORD1
+public KEYWORD1
+return KEYWORD1
+short KEYWORD1
+static KEYWORD1
+strictfp KEYWORD1
+super KEYWORD1
+switch KEYWORD1
+synchronized KEYWORD1
+this KEYWORD1
+throw KEYWORD1
+throws KEYWORD1
+transient KEYWORD1
+true KEYWORD1
+try KEYWORD1
+void KEYWORD1
+volatile KEYWORD1
+while KEYWORD1
+
+# Depricated API
+
+arraycopy KEYWORD2 arraycopy_
+openStream KEYWORD2 openStream_
+
+
+# KEYWORD2 specifies methods and functions
+
+cache KEYWORD2
+
+
+# THE TEXT ABOVE IS HAND-WRITTEN AND FOUND IN THE FILE "keywords_base.txt"
+# THE TEXT BELOW IS AUTO-GENERATED
+
+
+abs KEYWORD2 abs_
+acos KEYWORD2 acos_
++= addassign
++ addition
+alpha KEYWORD2 alpha_
+ambient KEYWORD2 ambient_
+ambientLight KEYWORD2 ambientLight_
+append KEYWORD2 append_
+applyMatrix KEYWORD2 applyMatrix_
+arc KEYWORD2 arc_
+Array KEYWORD1 Array
+[] arrayaccess
+arrayCopy KEYWORD2 arrayCopy_
+ArrayList KEYWORD1 ArrayList
+asin KEYWORD2 asin_
+= assign
+atan KEYWORD2 atan_
+atan2 KEYWORD2 atan2_
+background KEYWORD2 background_
+beginCamera KEYWORD2 beginCamera_
+beginRaw KEYWORD2 beginRaw_
+beginRecord KEYWORD2 beginRecord_
+beginShape KEYWORD2 beginShape_
+bezier KEYWORD2 bezier_
+bezierDetail KEYWORD2 bezierDetail_
+bezierPoint KEYWORD2 bezierPoint_
+bezierTangent KEYWORD2 bezierTangent_
+bezierVertex KEYWORD2 bezierVertex_
+binary KEYWORD2 binary_
+binary KEYWORD2 bitwiseAND_
+| bitwiseOR
+blend KEYWORD2 blend_
+blendColor KEYWORD2 blendColor_
+blue KEYWORD2 blue_
+boolean KEYWORD1 boolean
+boolean KEYWORD2 boolean_
+box KEYWORD2 box_
+break KEYWORD1 break
+brightness KEYWORD2 brightness_
+byte KEYWORD1 byte
+byte KEYWORD2 byte_
+camera KEYWORD2 camera_
+case KEYWORD1 case
+ceil KEYWORD2 ceil_
+char KEYWORD1 char
+char KEYWORD2 char_
+char KEYWORD2 class_
+color KEYWORD2 color_
+color KEYWORD1 color_datatype
+colorMode KEYWORD2 colorMode_
+, comma
+// comment
+concat KEYWORD2 concat_
+?: KEYWORD1 conditional_
+constrain KEYWORD2 constrain_
+continue KEYWORD1 continue
+copy KEYWORD2 copy_
+cos KEYWORD2 cos_
+createFont KEYWORD2 createFont_
+createGraphics KEYWORD2 createGraphics_
+createImage KEYWORD2 createImage_
+createInput KEYWORD2 createInput_
+createOutput KEYWORD2 createOutput_
+createReader KEYWORD2 createReader_
+createWriter KEYWORD2 createWriter_
+{} curlybraces
+cursor KEYWORD2 cursor_
+curve KEYWORD2 curve_
+curveDetail KEYWORD2 curveDetail_
+curvePoint KEYWORD2 curvePoint_
+curveTangent KEYWORD2 curveTangent_
+curveTightness KEYWORD2 curveTightness_
+curveVertex KEYWORD2 curveVertex_
+day KEYWORD2 day_
+-- decrement
+default KEYWORD1 default
+degrees KEYWORD2 degrees_
+delay KEYWORD2 delay_
+directionalLight KEYWORD2 directionalLight_
+dist KEYWORD2 dist_
+/ divide
+/= divideassign
+/** doccomment
+. dot
+double KEYWORD1 double
+draw KEYWORD3 draw_
+ellipse KEYWORD2 ellipse_
+ellipseMode KEYWORD2 ellipseMode_
+else KEYWORD1 else
+emissive KEYWORD2 emissive_
+endCamera KEYWORD2 endCamera_
+endRaw KEYWORD2 endRaw_
+endRecord KEYWORD2 endRecord_
+endShape KEYWORD2 endShape_
+== equality
+exit KEYWORD2 exit_
+exp KEYWORD2 exp_
+expand KEYWORD2 expand_
+extends KEYWORD1 extends
+false KEYWORD1 false
+fill KEYWORD2 fill_
+filter KEYWORD2 filter_
+final KEYWORD1 final
+float KEYWORD1 float
+float KEYWORD2 float_
+floor KEYWORD2 floor_
+focused LITERAL2 focused
+for KEYWORD1 for_
+frameCount LITERAL2 frameCount
+frameRate KEYWORD2 frameRate_
+frameRate LITERAL2 frameRate
+frustum KEYWORD2 frustum_
+get KEYWORD2 get_
+< greaterthan
+<= greaterthanorequalto
+green KEYWORD2 green_
+HALF_PI LITERAL2 HALF_PI
+HashMap KEYWORD1 HashMap
+height LITERAL2 height
+hex KEYWORD2 hex_
+hint KEYWORD2 hint_
+hour KEYWORD2 hour_
+hue KEYWORD2 hue_
+if KEYWORD1 if_
+image KEYWORD2 image_
+imageMode KEYWORD2 imageMode_
+implements KEYWORD1 implements
+import KEYWORD1 import
+++ increment
+!= inequality
+int KEYWORD1 int
+int KEYWORD2 int_
+join KEYWORD2 join_
+key LITERAL2 key
+keyCode LITERAL2 keyCode
+keyPressed KEYWORD2 keyPressed_
+keyPressed LITERAL2 keyPressed
+keyReleased KEYWORD2 keyReleased_
+keyTyped KEYWORD2 keyTyped_
+<< leftshift
+lerp KEYWORD2 lerp_
+lerpColor KEYWORD2 lerpColor_
+< lessthan
+<= lessthanorequalto
+lightFalloff KEYWORD2 lightFalloff_
+lights KEYWORD2 lights_
+lightSpecular KEYWORD2 lightSpecular_
+line KEYWORD2 line_
+link KEYWORD2 link_
+loadBytes KEYWORD2 loadBytes_
+loadFont KEYWORD2 loadFont_
+loadImage KEYWORD2 loadImage_
+loadPixels KEYWORD2 loadPixels_
+loadShape KEYWORD2 loadShape_
+loadStrings KEYWORD2 loadStrings_
+log KEYWORD2 log_
+&& logicalAND
+! logicalNOT
+|| logicalOR
+long KEYWORD1 long
+loop KEYWORD2 loop_
+mag KEYWORD2 mag_
+map KEYWORD2 map_
+match KEYWORD2 match_
+matchAll KEYWORD2 matchAll_
+max KEYWORD2 max_
+millis KEYWORD2 millis_
+min KEYWORD2 min_
+- minus
+minute KEYWORD2 minute_
+modelX KEYWORD2 modelX_
+modelY KEYWORD2 modelY_
+modelZ KEYWORD2 modelZ_
+% modulo
+month KEYWORD2 month_
+mouseButton LITERAL2 mouseButton
+mouseClicked KEYWORD2 mouseClicked_
+mouseDragged KEYWORD2 mouseDragged_
+mouseMoved KEYWORD2 mouseMoved_
+mousePressed KEYWORD2 mousePressed_
+mousePressed LITERAL2 mousePressed
+mouseReleased KEYWORD2 mouseReleased_
+mouseX LITERAL2 mouseX
+mouseY LITERAL2 mouseY
+/* multilinecomment
+* multiply
+*= multiplyassign
+new KEYWORD1 new
+nf KEYWORD2 nf_
+nfc KEYWORD2 nfc_
+nfp KEYWORD2 nfp_
+nfs KEYWORD2 nfs_
+noCursor KEYWORD2 noCursor_
+noFill KEYWORD2 noFill_
+noise KEYWORD2 noise_
+noiseDetail KEYWORD2 noiseDetail_
+noiseSeed KEYWORD2 noiseSeed_
+noLights KEYWORD2 noLights_
+noLoop KEYWORD2 noLoop_
+norm KEYWORD2 norm_
+normal KEYWORD2 normal_
+noSmooth KEYWORD2 noSmooth_
+noStroke KEYWORD2 noStroke_
+noTint KEYWORD2 noTint_
+null KEYWORD1 null
+Object KEYWORD1 Object
+online LITERAL2 online
+open KEYWORD2 open_
+ortho KEYWORD2 ortho_
+param KEYWORD2 param_
+() parentheses
+perspective KEYWORD2 perspective_
+PFont KEYWORD1 PFont
+list KEYWORD2 PFont_list_
+PGraphics KEYWORD1 PGraphics
+beginDraw KEYWORD2 PGraphics_beginDraw_
+endDraw KEYWORD2 PGraphics_endDraw_
+PI LITERAL2 PI
+PImage KEYWORD1 PImage
+alpha KEYWORD2 PImage_alpha_
+blend KEYWORD2 PImage_blend_
+copy KEYWORD2 PImage_copy_
+filter KEYWORD2 PImage_filter_
+get KEYWORD2 PImage_get_
+height LITERAL2 PImage_height
+loadPixels KEYWORD2 PImage_loadPixels_
+mask KEYWORD2 PImage_mask_
+pixels LITERAL2 PImage_pixels
+resize KEYWORD2 PImage_resize_
+save KEYWORD2 PImage_save_
+set KEYWORD2 PImage_set_
+updatePixels KEYWORD2 PImage_updatePixels_
+width LITERAL2 PImage_width
+pixels LITERAL2 pixels
+pmouseX LITERAL2 pmouseX
+pmouseY LITERAL2 pmouseY
+point KEYWORD2 point_
+point KEYWORD2 pointLight_
+popMatrix KEYWORD2 popMatrix_
+popStyle KEYWORD3 popStyle_
+pow KEYWORD2 pow_
+print KEYWORD2 print_
+printCamera KEYWORD2 printCamera_
+println KEYWORD2 println_
+printMatrix KEYWORD2 printMatrix_
+printProjection KEYWORD2 printProjection_
+PrintWriter KEYWORD1 PrintWriter
+close KEYWORD2 PrintWriter_close_
+flush KEYWORD2 PrintWriter_flush_
+print KEYWORD2 PrintWriter_print_
+println KEYWORD2 PrintWriter_println_
+private KEYWORD1 private
+PShape KEYWORD1 PShape
+disableStyle KEYWORD2 PShape_disableStyle_
+enableStyle KEYWORD2 PShape_enableStyle_
+getChild KEYWORD2 PShape_getChild_
+getHeight KEYWORD2 PShape_getHeight_
+getWidth KEYWORD2 PShape_getWidth_
+isVisible KEYWORD2 PShape_isVisible_
+resetMatrix KEYWORD2 PShape_resetMatrix_
+rotate KEYWORD2 PShape_rotate_
+rotateX KEYWORD2 PShape_rotateX_
+rotateY KEYWORD2 PShape_rotateY_
+rotateZ KEYWORD2 PShape_rotateZ_
+scale KEYWORD2 PShape_scale_
+setVisible KEYWORD2 PShape_setVisible_
+translate KEYWORD2 PShape_translate_
+public KEYWORD1 public
+pushMatrix KEYWORD2 pushMatrix_
+pushStyle KEYWORD3 pushStyle_
+PVector KEYWORD1 PVector
+add KEYWORD2 PVector_add_
+angleBetween KEYWORD2 PVector_angleBetween_
+array KEYWORD2 PVector_array_
+copy KEYWORD2 PVector_copy_
+cross KEYWORD2 PVector_cross_
+dist KEYWORD2 PVector_dist_
+div KEYWORD2 PVector_div_
+dot KEYWORD2 PVector_dot_
+get KEYWORD2 PVector_get_
+limit KEYWORD2 PVector_limit_
+mag KEYWORD2 PVector_mag_
+mult KEYWORD2 PVector_mult_
+normalize KEYWORD2 PVector_normalize_
+set KEYWORD2 PVector_set_
+sub KEYWORD2 PVector_sub_
+quad KEYWORD2 quad_
+radians KEYWORD2 radians_
+random KEYWORD2 random_
+randomSeed KEYWORD2 randomSeed_
+rect KEYWORD2 rect_
+rectMode KEYWORD2 rectMode_
+red KEYWORD2 red_
+redraw KEYWORD2 redraw_
+requestImage KEYWORD2 requestImage_
+resetMatrix KEYWORD2 resetMatrix_
+return KEYWORD1 return
+reverse KEYWORD2 reverse_
+<< rightshift
+rotate KEYWORD2 rotate_
+rotateX KEYWORD2 rotateX_
+rotateY KEYWORD2 rotateY_
+rotateZ KEYWORD2 rotateZ_
+round KEYWORD2 round_
+saturation KEYWORD2 saturation_
+save KEYWORD2 save_
+saveBytes KEYWORD2 saveBytes_
+saveFrame KEYWORD2 saveFrame_
+saveStream KEYWORD2 saveStream_
+saveStrings KEYWORD2 saveStrings_
+scale KEYWORD2 scale_
+screen LITERAL2 screen
+screenX KEYWORD2 screenX_
+screenY KEYWORD2 screenY_
+screenZ KEYWORD2 screenZ_
+second KEYWORD2 second_
+selectFolder KEYWORD2 selectFolder_
+selectInput KEYWORD2 selectInput_
+selectOutput KEYWORD2 selectOutput_
+; semicolon
+set KEYWORD2 set_
+setup KEYWORD3 setup_
+shape KEYWORD2 shape_
+shapeMode KEYWORD2 shapeMode_
+shininess KEYWORD2 shininess_
+shorten KEYWORD2 shorten_
+sin KEYWORD2 sin_
+size KEYWORD2 size_
+smooth KEYWORD2 smooth_
+sort KEYWORD2 sort_
+specular KEYWORD2 specular_
+sphere KEYWORD2 sphere_
+sphereDetail KEYWORD2 sphereDetail_
+splice KEYWORD2 splice_
+split KEYWORD2 split_
+splitTokens KEYWORD2 splitTokens_
+spotLight KEYWORD2 spotLight_
+sq KEYWORD2 sq_
+sqrt KEYWORD2 sqrt_
+static KEYWORD1 static
+status KEYWORD2 status_
+str KEYWORD2 str_
+String KEYWORD1 String
+charAt KEYWORD2 String_charAt_
+equals KEYWORD2 String_equals_
+indexOf KEYWORD2 String_indexOf_
+length KEYWORD2 String_length_
+substring KEYWORD2 String_substring_
+toLowerCase KEYWORD2 String_toLowerCase_
+toUpperCase KEYWORD2 String_toUpperCase_
+stroke KEYWORD2 stroke_
+strokeCap KEYWORD2 strokeCap_
+strokeJoin KEYWORD2 strokeJoin_
+strokeWeight KEYWORD2 strokeWeight_
+subset KEYWORD2 subset_
+-= subtractassign
+super KEYWORD1 super
+switch KEYWORD2 switch_
+tan KEYWORD2 tan_
+text KEYWORD2 text_
+textAlign KEYWORD2 textAlign_
+textAscent KEYWORD2 textAscent_
+textDescent KEYWORD2 textDescent_
+textFont KEYWORD2 textFont_
+textLeading KEYWORD2 textLeading_
+textMode KEYWORD2 textMode_
+textSize KEYWORD2 textSize_
+texture KEYWORD2 texture_
+textureMode KEYWORD2 textureMode_
+textWidth KEYWORD2 textWidth_
+this KEYWORD1 this
+tint KEYWORD2 tint_
+translate KEYWORD2 translate_
+triangle KEYWORD2 triangle_
+trim KEYWORD2 trim_
+true KEYWORD1 true
+TWO_PI LITERAL2 TWO_PI
+unbinary KEYWORD2 unbinary_
+unhex KEYWORD2 unhex_
+updatePixels KEYWORD2 updatePixels_
+vertex KEYWORD2 vertex_
+void KEYWORD1 void
+while KEYWORD1 while_
+width LITERAL2 width
+XMLElement KEYWORD1 XMLElement
+getChild KEYWORD2 XMLElement_getChild_
+getChildCount KEYWORD2 XMLElement_getChildCount_
+getChildren KEYWORD2 XMLElement_getChildren_
+getContent KEYWORD2 XMLElement_getContent_
+getFloatAttribute KEYWORD2 XMLElement_getFloatAttribute_
+getIntAttribute KEYWORD2 XMLElement_getIntAttribute_
+getName KEYWORD2 XMLElement_getName_
+getStringAttribute KEYWORD2 XMLElement_getStringAttribute_
+year KEYWORD2 year_
diff --git a/build/shared/lib/preferences.txt b/build/shared/lib/preferences.txt
new file mode 100755
index 000000000..c8fa1f840
--- /dev/null
+++ b/build/shared/lib/preferences.txt
@@ -0,0 +1,215 @@
+# !!!!!!!! UNLIKE PREVIOUS VERSIONS OF PROCESSING !!!!!!!!!!
+# DO NOT MODIFY THIS FILE, OR DELETE SETTINGS FROM THIS FILE
+
+# These are the default preferences. If you want to modify
+# them directly, use the per-user local version of the file:
+
+# Documents and Settings -> [username] -> Application Data ->
+# Processing -> preferences.txt (on Windows XP)
+
+# Users -> [username] -> AppData -> Roaming ->
+# Processing -> preferences.txt (on Windows Vista)
+
+# ~/Library -> Processing -> preferences.txt (on Mac OS X)
+
+# ~/.processing -> preferences.txt (on Linux)
+
+# The exact location of your preferences file can be found at
+# the bottom of the Preferences window inside Processing.
+
+# Because AppData and Application Data may be considered
+# hidden or system folders on Windows, you'll have to ensure
+# that they're visible in order to get at preferences.txt
+
+# You'll have problems running Processing if you incorrectly
+# modify lines in this file.
+
+
+# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+
+# DEFAULT PATHS FOR SKETCHBOOK AND SETTINGS
+
+# relative paths will be relative to processing.exe or procesing.app.
+# absolute paths may also be used.
+
+# note that this path should use forward slashes (like unix)
+# instead of \ on windows or : on macos or whatever else
+
+# If you don't want users to have their sketchbook default to
+# "My Documents/Processing" on Windows and "Documents/Processing" on OS X,
+# set this to another path that will be used by default.
+# Note that this path must exist already otherwise it won't see
+# the sketchbook folder, and will instead assume the sketchbook
+# has gone missing, and that it should instead use the default.
+#sketchbook.path=
+
+# if you don't want settings to go into "application data" on windows
+# and "library" on macosx, set this to the alternate location.
+#settings.path=data
+
+# temporary build path, normally this goes into the default
+# "temp" folder for that platform (as defined by java)
+# but this can be used to set a specific file in case of problems
+#build.path=build
+
+# By default, no sketches currently open
+last.sketch.count=0
+
+
+# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+
+# by default, check the processing server for any updates
+# (please avoid disabling, this also helps us know basic numbers
+# on how many people are using Processing)
+update.check = true
+
+# on windows, automatically associate .pde files with processing.exe
+platform.auto_file_type_associations = true
+
+# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+
+# default size for the main window
+default.window.width = 500
+default.window.height = 600
+
+# font size for editor
+editor.font=Monospaced,plain,12
+# Monaco is nicer on Mac OS X, so use that explicitly
+editor.font.macosx = Monaco,plain,10
+
+# anti-aliased text, turned off by default
+editor.antialias=false
+
+# color to be used for background when 'external editor' enabled
+editor.external=false
+
+# caret blinking
+editor.caret.blink=true
+
+# area that's not in use by the text (replaced with tildes)
+editor.invalid=false
+
+console = true
+console.output.file = stdout.txt
+console.error.file = stderr.txt
+console.lines = 4
+
+# set to false to disable automatically clearing the console
+# each time 'run' is hit
+console.auto_clear = true
+
+# set the maximum number of lines remembered by the console
+# the default is 500, lengthen at your own peril
+console.length = 500
+
+# convert tabs to spaces? how many spaces?
+editor.tabs.expand = true
+editor.tabs.size = 2
+
+# automatically indent each line
+editor.indent = true
+
+# size of divider between editing area and the console
+editor.divider.size = 0
+# the larger divider on windows is ugly with the little arrows
+# this makes it large enough to see (mouse changes) and use,
+# but keeps it from being annoyingly obtrusive
+editor.divider.size.windows = 2
+
+# any additional java options when running externally
+# (for applets that are run external to the environment...
+# those with a code folder, or using any libraries)
+# if you hose this and can't run things, it's your own durn fault
+run.options =
+
+# settings for the -XmsNNNm and -XmxNNNm command line option
+run.options.memory = false
+run.options.memory.initial = 64
+run.options.memory.maximum = 256
+
+# example of increasing the memory size for applets run externally
+#run.options = -Xms128m -Xmx1024m
+
+# index of the default display to use for present mode
+# (this setting not yet completely implemented)
+run.display = 1
+
+# set internally
+#run.window.bgcolor=
+
+# set to false to open a new untitled window when closing the last window
+# (otherwise, the environment will quit)
+# default to the relative norm for the different platforms,
+# but the setting can be changed in the prefs dialog anyway
+#sketchbook.closing_last_window_quits = true
+#sketchbook.closing_last_window_quits.macosx = false
+
+
+# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+
+#history.recording = true
+
+# for advanced users, enable option to export a library
+#export.library = false
+
+# which platforms to export by default
+export.application.platform.windows = true
+export.application.platform.macosx = true
+export.application.platform.linux = true
+
+# whether or not to export as full screen (present) mode
+export.application.fullscreen = false
+
+# whether to show the stop button when exporting to application
+export.application.stop = true
+
+# false will place all exported files into a single .jar
+export.applet.separate_jar_files = false
+
+# set to false to no longer delete applet or application folders before export
+export.delete_target_folder = true
+
+# may be useful when attempting to debug the preprocessor
+preproc.save_build_files=false
+
+# allows various preprocessor features to be toggled
+# in case they are causing problems
+
+# preprocessor: pde.g
+preproc.color_datatype = true
+preproc.web_colors = true
+preproc.enhanced_casting = true
+
+# preprocessor: PdeEmitter.java
+preproc.substitute_floats = true
+#preproc.substitute_image = false
+#preproc.substitute_font = false
+
+# auto-convert non-ascii chars to unicode escape sequences
+preproc.substitute_unicode = true
+
+# PdePreproc.java
+# writes out the parse tree as parseTree.xml, which can be usefully
+# viewed in (at least) Mozilla or IE. useful when debugging the preprocessor.
+preproc.output_parse_tree = false
+
+# imports to use by default (changed for 0149, some imports removed)
+preproc.imports = java.applet,java.awt,java.awt.image,java.awt.event,java.io,java.net,java.text,java.util,java.util.zip,java.util.regex
+
+# set the browser to be used on linux
+browser.linux = mozilla
+
+# set to the program to be used for launching apps on linux
+#launcher.linux = gnome-open
+
+# FULL SCREEN (PRESENT MODE)
+run.present.bgcolor = #666666
+run.present.stop.color = #cccccc
+# starting in release 0159, don't use full screen exclusive anymore
+run.present.exclusive = false
+# use this by default to hide the menu bar and dock on osx
+run.present.exclusive.macosx = true
diff --git a/build/shared/lib/theme/buttons.gif b/build/shared/lib/theme/buttons.gif
new file mode 100644
index 000000000..3d8facd00
Binary files /dev/null and b/build/shared/lib/theme/buttons.gif differ
diff --git a/build/shared/lib/theme/resize.gif b/build/shared/lib/theme/resize.gif
new file mode 100644
index 000000000..630be1e26
Binary files /dev/null and b/build/shared/lib/theme/resize.gif differ
diff --git a/build/shared/lib/theme/tab-sel-left.gif b/build/shared/lib/theme/tab-sel-left.gif
new file mode 100644
index 000000000..bdee43c25
Binary files /dev/null and b/build/shared/lib/theme/tab-sel-left.gif differ
diff --git a/build/shared/lib/theme/tab-sel-menu.gif b/build/shared/lib/theme/tab-sel-menu.gif
new file mode 100644
index 000000000..d926650e7
Binary files /dev/null and b/build/shared/lib/theme/tab-sel-menu.gif differ
diff --git a/build/shared/lib/theme/tab-sel-mid.gif b/build/shared/lib/theme/tab-sel-mid.gif
new file mode 100644
index 000000000..fa8ed45fc
Binary files /dev/null and b/build/shared/lib/theme/tab-sel-mid.gif differ
diff --git a/build/shared/lib/theme/tab-sel-right.gif b/build/shared/lib/theme/tab-sel-right.gif
new file mode 100644
index 000000000..d901fdba4
Binary files /dev/null and b/build/shared/lib/theme/tab-sel-right.gif differ
diff --git a/build/shared/lib/theme/tab-unsel-left.gif b/build/shared/lib/theme/tab-unsel-left.gif
new file mode 100644
index 000000000..eea22d8d8
Binary files /dev/null and b/build/shared/lib/theme/tab-unsel-left.gif differ
diff --git a/build/shared/lib/theme/tab-unsel-menu.gif b/build/shared/lib/theme/tab-unsel-menu.gif
new file mode 100644
index 000000000..a1720a589
Binary files /dev/null and b/build/shared/lib/theme/tab-unsel-menu.gif differ
diff --git a/build/shared/lib/theme/tab-unsel-mid.gif b/build/shared/lib/theme/tab-unsel-mid.gif
new file mode 100644
index 000000000..a2c5497b8
Binary files /dev/null and b/build/shared/lib/theme/tab-unsel-mid.gif differ
diff --git a/build/shared/lib/theme/tab-unsel-right.gif b/build/shared/lib/theme/tab-unsel-right.gif
new file mode 100644
index 000000000..91c03f5a9
Binary files /dev/null and b/build/shared/lib/theme/tab-unsel-right.gif differ
diff --git a/build/shared/lib/theme/theme.txt b/build/shared/lib/theme/theme.txt
new file mode 100644
index 000000000..c6da56f0d
--- /dev/null
+++ b/build/shared/lib/theme/theme.txt
@@ -0,0 +1,101 @@
+# GUI - STATUS
+status.notice.fgcolor = #000000
+status.notice.bgcolor = #818b95
+status.error.fgcolor = #ffffff
+status.error.bgcolor = #662000
+status.edit.fgcolor = #000000
+status.edit.bgcolor = #cc9900
+status.font = SansSerif,plain,12
+
+# GUI - TABS
+# settings for the tabs at the top
+# (tab images are stored in the lib/theme folder)
+header.bgcolor = #818b95
+header.text.selected.color = #1a1a00
+header.text.unselected.color = #ffffff
+header.text.font = SansSerif,plain,12
+
+# GUI - CONSOLE
+console.font = Monospaced,plain,11
+console.font.macosx = Monaco,plain,10
+console.color = #000000
+console.output.color = #cccccc
+console.error.color = #ff3000
+
+# GUI - BUTTONS
+buttons.bgcolor = #4a545e
+buttons.status.font = SansSerif,plain,12
+buttons.status.color = #ffffff
+
+# GUI - LINESTATUS
+linestatus.color = #ffffff
+linestatus.bgcolor = #29333d
+
+# EDITOR - DETAILS
+
+# foreground and background colors
+editor.fgcolor = #000000
+editor.bgcolor = #ffffff
+
+# highlight for the current line
+editor.linehighlight.color=#e2e2e2
+# highlight for the current line
+editor.linehighlight=true
+
+# caret blinking and caret color
+editor.caret.color = #333300
+
+# color to be used for background when 'external editor' enabled
+editor.external.bgcolor = #c8d2dc
+
+# selection color
+editor.selection.color = #ffcc00
+
+# area that's not in use by the text (replaced with tildes)
+editor.invalid.style = #7e7e7e,bold
+
+# little pooties at the end of lines that show where they finish
+editor.eolmarkers = false
+editor.eolmarkers.color = #999999
+
+# bracket/brace highlighting
+editor.brackethighlight = true
+editor.brackethighlight.color = #006699
+
+
+# TEXT - KEYWORDS
+
+# e.g abstract, final, private
+editor.keyword1.style = #cc6600,plain
+
+# e.g. beginShape, point, line
+editor.keyword2.style = #cc6600,plain
+
+# e.g. byte, char, short, color
+editor.keyword3.style = #cc6600,bold
+
+
+# TEXT - LITERALS
+
+# constants: e.g. null, true, this, RGB, TWO_PI
+editor.literal1.style = #006699,plain
+
+# p5 built in variables: e.g. mouseX, width, pixels
+editor.literal2.style = #006699,plain
+
+# e.g. + - = /
+editor.operator.style = #000000,plain
+
+# ?? maybe this is for words followed by a colon
+# like in case statements or goto
+editor.label.style = #7e7e7e,bold
+
+
+# TEXT - COMMENTS
+editor.comment1.style = #7e7e7e,plain
+editor.comment2.style = #7e7e7e,plain
+
+
+# LINE STATUS - editor line number status bar at the bottom of the screen
+linestatus.font = SansSerif,plain,10
+linestatus.height = 20
diff --git a/build/shared/libraries/howto.txt b/build/shared/libraries/howto.txt
new file mode 100644
index 000000000..9865ab19a
--- /dev/null
+++ b/build/shared/libraries/howto.txt
@@ -0,0 +1,5 @@
+This file has been replaced by an entire section of dev.processing.org
+dedicated to libraries, people who make libraries, and people who
+love library development trivia. The new page can be found here:
+
+http://dev.processing.org/libraries/
diff --git a/build/shared/libraries/javascript/library/export.txt b/build/shared/libraries/javascript/library/export.txt
new file mode 100644
index 000000000..a642bb596
--- /dev/null
+++ b/build/shared/libraries/javascript/library/export.txt
@@ -0,0 +1,6 @@
+# don't actually export anything.. this is only to link against
+# inside of the p5 environment
+applet=
+
+# for an application, export to prevent from breaking
+application=javascript.jar
\ No newline at end of file
diff --git a/build/shared/libraries/javascript/library/javascript.jar b/build/shared/libraries/javascript/library/javascript.jar
new file mode 100644
index 000000000..93c7b9251
Binary files /dev/null and b/build/shared/libraries/javascript/library/javascript.jar differ
diff --git a/build/shared/libraries/minim/library/jl1.0.jar b/build/shared/libraries/minim/library/jl1.0.jar
new file mode 100755
index 000000000..17f7c0aa7
Binary files /dev/null and b/build/shared/libraries/minim/library/jl1.0.jar differ
diff --git a/build/shared/libraries/minim/library/jsminim.jar b/build/shared/libraries/minim/library/jsminim.jar
new file mode 100755
index 000000000..4e6f6e564
Binary files /dev/null and b/build/shared/libraries/minim/library/jsminim.jar differ
diff --git a/build/shared/libraries/minim/library/minim-spi.jar b/build/shared/libraries/minim/library/minim-spi.jar
new file mode 100755
index 000000000..4760de485
Binary files /dev/null and b/build/shared/libraries/minim/library/minim-spi.jar differ
diff --git a/build/shared/libraries/minim/library/minim.jar b/build/shared/libraries/minim/library/minim.jar
new file mode 100755
index 000000000..eb053ccec
Binary files /dev/null and b/build/shared/libraries/minim/library/minim.jar differ
diff --git a/build/shared/libraries/minim/library/mp3spi1.9.4.jar b/build/shared/libraries/minim/library/mp3spi1.9.4.jar
new file mode 100755
index 000000000..019b86c93
Binary files /dev/null and b/build/shared/libraries/minim/library/mp3spi1.9.4.jar differ
diff --git a/build/shared/libraries/minim/library/tritonus_aos.jar b/build/shared/libraries/minim/library/tritonus_aos.jar
new file mode 100755
index 000000000..4a02386d4
Binary files /dev/null and b/build/shared/libraries/minim/library/tritonus_aos.jar differ
diff --git a/build/shared/libraries/minim/library/tritonus_share.jar b/build/shared/libraries/minim/library/tritonus_share.jar
new file mode 100755
index 000000000..bb367d17e
Binary files /dev/null and b/build/shared/libraries/minim/library/tritonus_share.jar differ
diff --git a/build/shared/libraries/minim/license.txt b/build/shared/libraries/minim/license.txt
new file mode 100755
index 000000000..d511905c1
--- /dev/null
+++ b/build/shared/libraries/minim/license.txt
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ , 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/build/shared/libraries/minim/version.txt b/build/shared/libraries/minim/version.txt
new file mode 100755
index 000000000..10bf840ed
--- /dev/null
+++ b/build/shared/libraries/minim/version.txt
@@ -0,0 +1 @@
+2.0.1
\ No newline at end of file
diff --git a/build/shared/reference.zip b/build/shared/reference.zip
new file mode 100755
index 000000000..baa5e4ee2
Binary files /dev/null and b/build/shared/reference.zip differ
diff --git a/build/shared/revisions.txt b/build/shared/revisions.txt
new file mode 100644
index 000000000..f50448527
--- /dev/null
+++ b/build/shared/revisions.txt
@@ -0,0 +1,241 @@
+PROCESSING 1.0.3 (REV 0165) - 24 February 2009
+
+Bug fix release to repair a couple of regressions caused by changes in 1.0.2,
+as well as a couple other new problems encountered since.
+
+[ bug fixes ]
+
++ endRecord or endRaw produces a RuntimeException with the PDF library
+ http://dev.processing.org/bugs/show_bug.cgi?id=1169
+
++ Problem with beginRaw/endRaw and OpenGL
+ http://dev.processing.org/bugs/show_bug.cgi?id=1171
+
++ Set strokeWeight on points and lines with begin/endRaw
+ http://dev.processing.org/bugs/show_bug.cgi?id=1172
+
++ Fix strokeWeight quirks with P3D when used with points and lines
+
++ ArrayIndexOutOfBoundsException with point()
+ http://dev.processing.org/bugs/show_bug.cgi?id=1168
+
+[ changes ]
+
++ Update to iText 2.1.4 for the PDF library
+
+
+PROCESSING 1.0.2 (REV 0164) - 21 February 2009
+
+This release fixes many bugs and adds two minor functions to the XML library.
+
+[ bug fixes ]
+
++ Empty "code" folder causing problems with Export
+ http://dev.processing.org/bugs/show_bug.cgi?id=1084
+
++ Sketches not loading when .pde file is opened from the Windows Explorer
+ on Asian Windows systems.
+ http://dev.processing.org/bugs/show_bug.cgi?id=1089
+
++ Disable copying of metadata and resource forks in OS X build
+ http://dev.processing.org/bugs/show_bug.cgi?id=1098
+
++ Suppress goofy Apple error message about JVMArchs
+
++ StringIndexOutOfBoundsException caused by import statements with no dots
+ http://dev.processing.org/bugs/show_bug.cgi?id=1145
+
++ Pressing in "Are you sure you want to Quit?" dialog causes quit
+ http://dev.processing.org/bugs/show_bug.cgi?id=1134
+
++ Fix QUADS and QUAD_STRIP with P2D
+ http://dev.processing.org/bugs/show_bug.cgi?id=1162
+
++ ArrayIndexOutOfBoundsException when drawing curves in P3D and OPENGL
+ http://dev.processing.org/bugs/show_bug.cgi?id=1153
+
++ Problems with negatve arc() angles in OpenGL, P3D, other inconsistencies
+ http://dev.processing.org/bugs/show_bug.cgi?id=1095
+
++ requestImage() causing problems with JAVA2D
+
++ Fix minor strokeWeight bug with OpenGL
+
++ Minor bug fix to SVG files that weren't being resized properly
+
++ OpenGL is rendering darker in 0149+
+ http://dev.processing.org/bugs/show_bug.cgi?id=958
+ Thanks to Dave Bollinger for tracking this down and providing a solution
+
++ OutOfMemoryError with ellipse() in P3D and OPENGL
+ http://dev.processing.org/bugs/show_bug.cgi?id=1086
+
++ ArrayIndexOutOfBoundsException with P3D and OPENGL
+ http://dev.processing.org/bugs/show_bug.cgi?id=1117
+
++ point(x,y) ignores noStroke() in some renderers
+ http://dev.processing.org/bugs/show_bug.cgi?id=1090
+
++ Fix Windows startup problem when scheme coloring was odd
+ http://dev.processing.org/bugs/show_bug.cgi?id=1109
+ Changes to the system theme could cause Processing to not launch
+
++ Fix several point() problems with P3D
+ http://dev.processing.org/bugs/show_bug.cgi?id=1110
+
++ nextPage() not working properly with PDF as the renderer
+ http://dev.processing.org/bugs/show_bug.cgi?id=1131
+
++ Save style information when nextPage() is called in PDF renderer
+
++ beginRaw() broken (no DXF, etc working)
+ http://dev.processing.org/bugs/show_bug.cgi?id=1099
+ http://dev.processing.org/bugs/show_bug.cgi?id=1144
+
++ Fix algorithm for quadratic to cubic curve conversion
+ http://dev.processing.org/bugs/show_bug.cgi?id=1122
+ Thanks to user bits.in.shambles for providing a fix.
+
++ tint() not working in P2D
+ http://dev.processing.org/bugs/show_bug.cgi?id=1132
+
++ blend() y coordinates inverted when using OpenGL
+ http://dev.processing.org/bugs/show_bug.cgi?id=1137
+
++ Fix for getChild() and getChildren() with XML elements that have null names
+
+[ additions ]
+
++ Added listChildren() method to XMLElement
+
++ Added optional toString(boolean) parameter to enable/disable indents
+ in XMLElement
+
+
+. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+
+
+PROCESSING 1.0.1 (REV 0163) - 29 November 2008
+
+Processing 1.0 has arrived! You can read an overview of changes introduced
+in the last few months here: http://processing.org/reference/changes.html
+
+Also see the "known issues" section of the troubleshooting page:
+http://processing.org/reference/troubleshooting/#known
+
+This release (1.0.1) fixes a handful of issues that only showed up once we
+had more testing, particularly with the wider audience we've received in the
+past week following the announcement.
+
+[ bug fixes ]
+
++ ArrayIndexOutOfBoundsException with File > New
+ http://dev.processing.org/bugs/show_bug.cgi?id=1067
+
++ "CallStaticVoidMethod() threw an exception" on some Mac OS X machines
+ http://dev.processing.org/bugs/show_bug.cgi?id=1063
+ http://dev.processing.org/bugs/show_bug.cgi?id=1078
+
++ "editor.indent" preference setting does not work properly
+ http://dev.processing.org/bugs/show_bug.cgi?id=1073
+
++ Fixed some "An error occurred while starting the application" problems
+
++ Added a note about the Minim library to the changes page.
+
++ Disable parsing of regexps with the split() command
+ http://dev.processing.org/bugs/show_bug.cgi?id=1060
+
++ Fixed ArrayIndexOutOfBoundsException in ellipseImpl().
+ http://dev.processing.org/bugs/show_bug.cgi?id=1068
+
++ Fixed problem where small ellipses weren't showing up.
+
+[ changes ]
+
++ Implement multi-line tab via tab key (also outdent)
+ http://dev.processing.org/bugs/show_bug.cgi?id=1075
+
++ Code with 'import' and a space incorrectly parsed as an import statement
+ http://dev.processing.org/bugs/show_bug.cgi?id=1064
+
+
+. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+
+
+PROCESSING 1.0 (REV 0162) - 24 November 2008
+
+Processing 1.0 has arrived! You can read an overview of changes introduced
+in the last few months here: http://processing.org/reference/changes.html
+
+[ known issues ]
+
++ Sketches that size(w, h, OPENGL) and do not clear the background on each
+ frame can cause major flickering or problems when the screen clears anyway.
+ There are several possible solutions:
+
+ 1. You may need to disable the default 2x smoothing by using
+ hint(DISABLE_OPENGL_2X_SMOOTH).
+
+ 2. Update the drivers for your graphics card.
+
+ 3. Get a decent graphics card -- the OpenGL renderer is for advanced
+ use, we don't support using it with cheaper built-in graphics hardware
+ like the Intel GMA 950.
+
+ 4. If you're running Windows Vista, try disabling the Aero theme.
+
+ This flickering issue is being tracked here:
+ http://dev.processing.org/bugs/show_bug.cgi?id=1056
+
++ "An error occurred while starting the application" when launching
+ Processing.exe on Windows. This is a high priority however we cannot
+ reproduce it on any of our test machines, which has delayed a fix.
+ http://dev.processing.org/bugs/show_bug.cgi?id=986
+
++ With P2D, P3D, and OPENGL, series of connected lines (such as the stroke
+ around a polygon, triangle, or ellipse) produce unattractive results when
+ strokeWeight is set.
+ http://dev.processing.org/bugs/show_bug.cgi?id=955
+
++ Unlike most applications, the menu bar is inside the editor window when
+ Processing is used with Mac OS X 10.5. This is a workaround for an Apple
+ bug in Java 1.5 and 1.6 on Mac OS X 10.5 that causes the menu bar to be
+ so excessively slow that the application appears to have crashed.
+ http://dev.processing.org/bugs/show_bug.cgi?id=786
+
+ Please file a bug report with Apple at bugreporter.apple.com if you want
+ this fixed. The problem has existed since the spring, and we first filed
+ a bug with them in June, and we have received no indication that it when
+ it will be fixed, or if it will ever be fixed.
+
+ Or if you want to take your chances with the slow menu bar,
+ you can change the default setting in the Preferences window.
+
++ Sketches that use the video library plus OpenGL have a problem on some
+ OS X machines. The workaround is listed in Comment #16 of this bug:
+ http://dev.processing.org/bugs/show_bug.cgi?id=882#c16
+
++ Command line support arrived in a recent release, but is not working yet.
+ http://dev.processing.org/bugs/show_bug.cgi?id=1048
+
++ OpenGL rendering is more dim/darker in release 0149 and later.
+ http://dev.processing.org/bugs/show_bug.cgi?id=958
+ Any help tracking this down would be most appreciated.
+
++ The first few frames of OpenGL sketches on Windows run slowly.
+ http://dev.processing.org/bugs/show_bug.cgi?id=874
+
++ When used with P3D, strokeWeight does not interpolate the Z-coordinates
+ of the lines, which means that when rotated, these flat lines may
+ disappear. (Since, uh, lines are, you know, flat.) The OPENGL renderer
+ setting does not share this problem because it always draws lines
+ perpendicular to the screen (which we hope to do in a future release).
+ http://dev.processing.org/bugs/show_bug.cgi?id=956
+
+
+. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+
+
+in spite of their historical feel good campiness, i've removed the
+notes from earlier releases because this file was getting out of hand.
diff --git a/build/shared/tools/Mangler/make.sh b/build/shared/tools/Mangler/make.sh
new file mode 100755
index 000000000..e1c1ce37b
--- /dev/null
+++ b/build/shared/tools/Mangler/make.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+# The pde.jar file may be buried inside the .app file on Mac OS X.
+PDE=`find ../.. -name pde.jar`
+
+javac -target 1.5 \
+ -cp "../../lib/core.jar:$PDE" \
+ -d bin \
+ src/Mangler.java
+
+cd bin && zip -r ../tool/mangler.jar * && cd ..
diff --git a/build/shared/tools/Mangler/src/Mangler.java b/build/shared/tools/Mangler/src/Mangler.java
new file mode 100644
index 000000000..cfd527954
--- /dev/null
+++ b/build/shared/tools/Mangler/src/Mangler.java
@@ -0,0 +1,94 @@
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+/*
+ Part of the Processing project - http://processing.org
+
+ Copyright (c) 2008 Ben Fry and Casey Reas
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+package com.transformers.supermangletron;
+
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import javax.swing.JOptionPane;
+
+import processing.app.Editor;
+import processing.app.tools.Tool;
+
+
+/**
+ * Example Tools menu entry.
+ */
+public class Mangler implements Tool {
+ Editor editor;
+
+
+ public void init(Editor editor) {
+ this.editor = editor;
+ }
+
+
+ public String getMenuTitle() {
+ return "Mangle Selection";
+ }
+
+
+ public void run() {
+ String sketchName = editor.getSketch().getName();
+
+ Object[] options = { "Yes, please", "No, thanks" };
+ int result = JOptionPane.showOptionDialog(editor,
+ "Is " + sketchName +
+ " ready for destruction?",
+ "Super Mangle Tron",
+ JOptionPane.YES_NO_OPTION,
+ JOptionPane.QUESTION_MESSAGE,
+ null,
+ options,
+ options[1]);
+ if (result == JOptionPane.YES_OPTION) {
+ mangleSelection();
+ }
+ }
+
+
+ protected void mangleSelection() {
+ if (editor.isSelectionActive()) {
+ String selection = editor.getSelectedText();
+ char[] stuff = selection.toCharArray();
+ // Randomly swap a bunch of characters in the text
+ for (int i = 0; i < stuff.length / 10; i++) {
+ int a = (int) (Math.random() * stuff.length);
+ int b = (int) (Math.random() * stuff.length);
+ if (stuff[a] == '\n' || stuff[b] == '\n') {
+ continue; // skip newline characters
+ }
+ stuff[a] = selection.charAt(b);
+ stuff[b] = selection.charAt(a);
+ }
+ editor.startCompoundEdit();
+ editor.setSelectedText(new String(stuff));
+ editor.stopCompoundEdit();
+ editor.statusNotice("Now that feels better, doesn't it?");
+
+ } else {
+ editor.statusError("No selection, no dice.");
+ }
+ }
+}
diff --git a/build/shared/tools/howto.txt b/build/shared/tools/howto.txt
new file mode 100644
index 000000000..77df31c91
--- /dev/null
+++ b/build/shared/tools/howto.txt
@@ -0,0 +1,143 @@
+TOOLS IN PROCESSING
+
+With initial help from code contributed by fjen, Processing release 0147 and
+later have a dynamically loading tools menu, which can be used to expand the
+environment in fun and fantastic ways.
+
+A Tool is a chunk of code that runs from the Tools menu. Tools are a means
+of building onto the Processing Development Environment without needing to
+rebuild the beast from source.
+
+The interface (at least for now) is extremely simple:
+
+
+package processing.app.tools.Tool;
+
+public interface Tool extends Runnable {
+
+ public void init(Editor editor);
+
+ public void run();
+
+ public String getMenuTitle();
+}
+
+
+The init() method is called when an Editor window first opens. This means
+you won't have access to a sketch object, or a GUI, and should only do minimal
+setup. (However it'd be a good idea to stash the "Editor" object for later.)
+
+The run() method will be called by the main application when the tool is
+selected from the menu. This is called using invokeLater(), so that the tool
+can safely use Swing and any other GUI yackety yack. If you're using a Frame,
+you'll need to detect whether the Frame is already open (and bring it to the
+front) or whether to create a new window.
+
+Faceless tools also use the run() method. You should avail yourselves of the
+statusNotice() and statusError() methods in Editor, to let the user know what's
+happened. (As per p. 107 of the Processing Development Environment Tools
+Reference User Interface Guide.)
+
+The getMenuTitle() method just returns the title for what should appear in the
+Tools menu. Not doing shortcuts for now, because resolving them between tools
+(and the rest of the interface) is fugly. We would also need additional
+modifiers for shift and alt. It just gets messy quick. Ordering in the Tools
+menu is alphabetical.
+
+
+//////////////////////////////////////////////////////////////
+
+
+Where to put Tools
+
+Core tools live inside the "tools" subfolder of the Processing distribution,
+however users should install "contributed" tools in their sketchbook folder,
+inside a subfolder named "tools".
+
+If a tool works only with a particular release of Processing, then it may make
+sense for the user to put things into the Processing tools folder, however we'd
+like to keep users out of there as much as possible. In fact, it may not be
+visible in future releases of Processing (for instance, on Mac OS X, the tools
+folder is hidden inside the .app bundle).
+
+Tools should be laid out similar to libraries, though the structure is a little
+more flexible. The tool folder should be the name of the main class (without
+its package name but using the same capitalization), and have a subfolder named
+"tool" that contains the .jar and .zip files it uses. I'll use the included
+"Mangler" tool as an example.
+
+(This Tool is not built by default, due to a lack of non-dubious arguments
+regarding the usefulness of including (by default) a Tool that mangles code.)
+
+The folder should be called Mangler (note the capitalization), and contain:
+
+sketchbook/Mangler -> tool folder
+sketchbook/Mangler/tool -> location for code
+sketchbook/Mangler/tool/mangle.jar -> jar with one or more classes
+
+The naming of jar and zip files in the tool/* directory doesn't matter.
+
+When Processing loads, the jar and zip files will be searched for
+Mangler.class. Even though this tool is found in package poos.shoe,
+it will be sussed out. Package names are required.
+
+Loose .class files are not supported, use only jar and zip files.
+
+
+//////////////////////////////////////////////////////////////
+
+
+What You Can and Cannot Do
+
+The only API methods that are officially scrubbed and sanctioned by the
+Commissioner on Fair API and Proper Manners for use by the Tools classes
+are found in:
+
+processing.app.Base
+processing.app.Editor
+processing.app.Preferences
+processing.app.Sketch
+processing.app.SketchCode
+
+In fact, most of the API you should be talking to is inside Editor.
+Full API documentation can be found on dev.processing.org:
+http://dev.processing.org/reference/everything/
+(Keep in mind that this is not always perfectly up to date, but we'll try.)
+
+Of course, you're welcome to go spelunking through the rest of the API
+(that's where all the fun stuff is anyway), but don't be upset when something
+changes and breaks your tool and makes your users sad.
+
+Currently, native code is not supported with tools. This might be possible,
+but it's another potentially messy thing to dynamically add native library
+paths to running code. (See "Future Releases" below.)
+
+
+//////////////////////////////////////////////////////////////
+
+
+Future Releases
+
+In future releases, we are considering the following features:
+
+1. How shortcut keys are handled.
+ http://dev.processing.org/bugs/show_bug.cgi?id=140
+
+2. Whether to allow tools to dock into the Preferences panel.
+ http://dev.processing.org/bugs/show_bug.cgi?id=883
+
+3. A means to run native code from the Tools menu.
+ http://dev.processing.org/bugs/show_bug.cgi?id=884
+
+4. Methods for reorganizing the Tools menu, or placing contributed
+ Tools inside other menus (such as Edit or Sketch).
+ http://dev.processing.org/bugs/show_bug.cgi?id=885
+
+This is the first round of documentation for the Tools menu, we reserve the
+right to update, clarify, and change our mind in future releases.
+
+
+//////////////////////////////////////////////////////////////
+
+
+Ben Fry, last updated 19 August 2008
diff --git a/build/windows/dist.sh b/build/windows/dist.sh
new file mode 100755
index 000000000..12b6a4d0c
--- /dev/null
+++ b/build/windows/dist.sh
@@ -0,0 +1,113 @@
+#!/bin/sh
+
+REVISION=`head -1 ../../todo.txt | awk '{print $1}'`
+
+if [ $1 ]
+then
+ RELEASE=$1
+ echo Creating Processing release $RELEASE...
+else
+ RELEASE=$REVISION
+ echo Creating Processing distribution for revision $REVISION...
+fi
+
+# check to see if the version number in the app is correct
+# so that mikkel doesn't kick my ass
+VERSIONED=`cat ../../app/src/processing/app/Base.java | grep $REVISION`
+if [ -z "$VERSIONED" ]
+then
+ echo Fix the revision number in Base.java
+ exit
+fi
+
+./make.sh
+
+# remove any old boogers
+rm -rf processing
+rm -rf processing-*
+
+mkdir processing
+cp -r ../shared/lib processing/
+cp -r ../shared/libraries processing/
+cp -r ../shared/tools processing/
+
+if [ $1 ]
+then
+ # write the release version number into the output directory
+ echo $1 > processing/lib/version.txt
+fi
+
+cp ../../app/lib/antlr.jar processing/lib/
+cp ../../app/lib/ecj.jar processing/lib/
+cp ../../app/lib/jna.jar processing/lib/
+
+cp ../shared/revisions.txt processing/
+
+echo Extracting examples...
+unzip -q -d processing/ ../shared/examples.zip
+
+echo Extracting reference...
+unzip -q -d processing/ ../shared/reference.zip
+
+# add the libraries folder with source
+cp -r ../../net processing/libraries/
+cp -r ../../opengl processing/libraries/
+cp -r ../../serial processing/libraries/
+cp -r ../../video processing/libraries/
+cp -r ../../pdf processing/libraries/
+cp -r ../../dxf processing/libraries/
+
+# add java (jre) files
+unzip -q -d processing jre.zip
+
+# get platform-specific goodies from the dist dir
+cp launcher/processing.exe processing/
+
+# grab pde.jar and export from the working dir
+cp work/lib/pde.jar processing/lib/
+cp work/lib/core.jar processing/lib/
+
+# convert revisions.txt to windows LFs
+# the 2> is because the app is a little chatty
+unix2dos processing/revisions.txt 2> /dev/null
+unix2dos processing/lib/preferences.txt 2> /dev/null
+unix2dos processing/lib/keywords.txt 2> /dev/null
+
+# remove boogers
+find processing -name "*.bak" -exec rm -f {} ';'
+find processing -name "*~" -exec rm -f {} ';'
+find processing -name ".DS_Store" -exec rm -f {} ';'
+find processing -name "._*" -exec rm -f {} ';'
+find processing -name "Thumbs.db" -exec rm -f {} ';'
+
+# chmod +x the crew
+find processing -name "*.html" -exec chmod +x {} ';'
+find processing -name "*.dll" -exec chmod +x {} ';'
+find processing -name "*.exe" -exec chmod +x {} ';'
+find processing -name "*.html" -exec chmod +x {} ';'
+
+# clean out the cvs entries
+find processing -name "CVS" -exec rm -rf {} ';' 2> /dev/null
+find processing -name ".cvsignore" -exec rm -rf {} ';'
+find processing -name ".svn" -exec rm -rf {} ';' 2> /dev/null
+
+# zip it all up for release
+echo Packaging standard release...
+echo
+P5=processing-$RELEASE
+mv processing $P5
+zip -rq $P5.zip $P5
+# nah, keep the new directory around
+#rm -rf $P5
+
+# zip up another for experts
+#echo Expert release is disabled until further notice.
+echo Packaging expert release...
+echo
+cp -a $P5 $P5-expert
+# remove enormous java runtime
+rm -rf $P5-expert/java
+zip -rq $P5-expert.zip $P5-expert
+
+echo Done.
+
diff --git a/build/windows/export/Makefile b/build/windows/export/Makefile
new file mode 100755
index 000000000..0273e5b1d
--- /dev/null
+++ b/build/windows/export/Makefile
@@ -0,0 +1,22 @@
+CXXFLAGS = -mwindows -mno-cygwin -O2 -Wall
+#POBJS = launcher.o launcher-rc.o
+# don't want to include the p5 icons for the exported feller
+AOBJS = launcher.o
+
+#processing.exe: $(POBJS)
+# $(LINK.cc) $(CXXFLAGS) -o $@ $(POBJS)
+# cp processing.exe ../work/
+
+application.exe: $(AOBJS)
+ $(LINK.cc) $(CXXFLAGS) -DEXPORT -o $@ $(AOBJS)
+ cp application.exe ../work/lib/export/
+ cp application.exe ../../shared/lib/export/
+
+$(POBJS): Makefile
+
+#launcher-rc.o: launcher.rc
+# windres -i $< -o $@
+
+clean:
+ $(RM) $(OBJS) application.exe
+# $(RM) $(OBJS) processing.exe application.exe
diff --git a/build/windows/export/application.exe b/build/windows/export/application.exe
new file mode 100755
index 000000000..ea70a3a2d
Binary files /dev/null and b/build/windows/export/application.exe differ
diff --git a/build/windows/export/launcher.cpp b/build/windows/export/launcher.cpp
new file mode 100644
index 000000000..be6009d4b
--- /dev/null
+++ b/build/windows/export/launcher.cpp
@@ -0,0 +1,451 @@
+// -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+
+// if this code looks shitty, that's because it is. people are likely to have
+// the durndest things in their CLASSPATH and QTJAVA environment variables.
+// mostly because installers often mangle them without the user knowing.
+// so who knows where and when the quotes will show up. the code below is
+// based on a couple years of trial and error with processing releases.
+
+// For revision 0102, a lot of changes were made to deal with stripping
+// the quotes from the PATH, CLASSPATH, and QTJAVA environment variables.
+// Any elements of the PATH and CLASSPATH that don't exist (whether files
+// or directories) are also stripped out before being set.
+// (Bug 112)
+
+// The size of all of the strings was made sort of ambiguously large, since
+// 1) nothing is hurt by allocating an extra few bytes temporarily and
+// 2) if the user has a long path, and it gets copied five times over for the
+// CLASSPATH, the program runs the risk of crashing. Bad bad.
+
+// TODO this code leaks memory all over the place because nothing has been
+// done to properly handle creation/deletion of new strings.
+
+// TODO switch to unicode versions of all methods in order to better support
+// running on non-English (non-Roman especially) versions of Windows.
+
+#define ARGS_FILE_PATH "\\lib\\args.txt"
+
+#include
+#include
+#include
+
+
+void removeLineEndings(char *what);
+char *scrubPath(char *incoming);
+char *mallocChars(int count);
+void removeQuotes(char *quoted);
+void removeTrailingSlash(char *slashed);
+
+int STDCALL
+WinMain (HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmd, int nShow)
+{
+ // command line that was passed to this application
+ char *incoming_cmd_line = (char *)malloc(strlen(lpCmd + 1) * sizeof(char));
+ strcpy(incoming_cmd_line, lpCmd);
+
+ // get the full path to the application that was launched,
+ // drop the app name but keep the path
+ char *exe_directory = (char *)malloc(MAX_PATH * sizeof(char));
+ //*exe_directory = 0;
+ GetModuleFileName(NULL, exe_directory, MAX_PATH);
+ // remove the application name
+ *(strrchr(exe_directory, '\\')) = '\0';
+
+
+ // open the file that contains the main class name and java args
+
+ char *args_file_path = (char*)
+ malloc(strlen(exe_directory) * sizeof(char) +
+ strlen(ARGS_FILE_PATH) * sizeof(char) + 1);
+ strcpy(args_file_path, exe_directory);
+ strcat(args_file_path, ARGS_FILE_PATH);
+
+ char java_args[512];
+ char java_main_class[512];
+ char jar_list[512];
+ char *app_classpath = (char *)malloc(10 * strlen(exe_directory) + 4096);
+
+ FILE *argsfile = fopen(args_file_path, "r");
+ if (argsfile == NULL) {
+ sprintf(app_classpath,
+ "This program is missing the \"lib\" folder, "
+ "which should be located at\n%s",
+ exe_directory);
+ MessageBox(NULL, app_classpath, "Folder Missing", MB_OK);
+ return 0;
+ /*
+ sprintf(app_classpath,
+ "%s\\lib;"
+ "%s\\lib\\pde.jar;"
+ "%s\\lib\\core.jar;"
+ "%s\\lib\\jna.jar;"
+ "%s\\lib\\ecj.jar;"
+ "%s\\lib\\antlr.jar;",
+ exe_directory,
+ exe_directory, exe_directory,
+ exe_directory, exe_directory, exe_directory);
+ */
+
+ } else {
+ fgets(java_args, 511, argsfile);
+ removeLineEndings(java_args);
+ fgets(java_main_class, 511, argsfile);
+ removeLineEndings(java_main_class);
+ fgets(jar_list, 511, argsfile);
+ removeLineEndings(jar_list);
+
+ //MessageBox(NULL, java_args, "args", MB_OK);
+ //MessageBox(NULL, java_main_class, "class", MB_OK);
+ //MessageBox(NULL, jar_list, "jarlist", MB_OK);
+
+ app_classpath[0] = 0;
+ char *jar = (char*) strtok(jar_list, ",");
+ while (jar != NULL) {
+ char entry[1024];
+ sprintf(entry, "%s\\lib\\%s;", exe_directory, jar);
+ strcat(app_classpath, entry);
+ jar = (char*) strtok(NULL, ",");
+ }
+ fclose(argsfile);
+ }
+
+ //
+
+ char *cp = (char *)malloc(10 * strlen(exe_directory) + 4096);
+
+ // test to see if running with a java runtime nearby or not
+ char *testpath = (char *)malloc(MAX_PATH * sizeof(char));
+ *testpath = 0;
+ strcpy(testpath, exe_directory);
+ strcat(testpath, "\\java\\bin\\java.exe");
+ FILE *fp = fopen(testpath, "rb");
+ int local_jre_installed = (fp != NULL);
+ //char *rt_jar = (fp == NULL) ? "" : "java\\lib\\rt.jar;";
+ if (fp != NULL) fclose(fp); // argh! this was probably causing trouble
+
+ //const char *envClasspath = getenv("CLASSPATH");
+ //char *env_classpath = (char *)malloc(16384 * sizeof(char));
+
+ // ignoring CLASSPATH for now, because it's not needed
+ // and causes more trouble than it's worth [0060]
+ //env_classpath[0] = 0;
+
+ /*
+ // keep this code around since may be re-enabled later
+ if (getenv("CLASSPATH") != NULL) {
+ strcpy(env_classpath, getenv("CLASSPATH"));
+ if (env_classpath[0] == '\"') {
+ // starting quote in classpath.. yech
+ env_classpath++; // shitty.. i know..
+
+ int len = strlen(env_classpath);
+ if (env_classpath[len-1] == '\"') {
+ env_classpath[len-1] = 0;
+ } else {
+ // a starting quote but no ending quote.. ugh
+ // maybe throw an error
+ }
+ }
+ int last = strlen(env_classpath);
+ env_classpath[last++] = ';';
+ env_classpath[last] = 0;
+ } else {
+ env_classpath[0] = 0;
+ }
+ */
+
+ char *qtjava_path = (char *)malloc(16384 * sizeof(char));
+ qtjava_path[0] = 0;
+
+ if (getenv("QTJAVA") != NULL) {
+ //char *qtjava_temp = (char *)malloc(16384 * sizeof(char));
+ strcpy(qtjava_path, getenv("QTJAVA"));
+ removeQuotes(qtjava_path);
+
+ /*
+ //MessageBox(NULL, qtjava_temp, "QTJAVA", MB_OK);
+ if (qtjava_temp[0] == '\"') { // has quotes
+ // remove quotes by subsetting string by two
+ int qtjava_repaired_length = strlen(qtjava_temp) - 2;
+ strncpy(qtjava_path, &qtjava_temp[1], qtjava_repaired_length);
+ // terminate the string since strncpy ain't gonna do it
+ qtjava_path[qtjava_repaired_length] = 0;
+ //MessageBox(NULL, qtjava_path, "QTJAVA", MB_OK);
+ } else {
+ strcpy(qtjava_path, getenv("QTJAVA"));
+ }
+ */
+
+ FILE *fp = fopen(qtjava_path, "rb");
+ if (fp != NULL) {
+ fclose(fp); // found it, all set
+ strcat(qtjava_path, ";"); // add path separator
+ //MessageBox(NULL, "found 1", "msg", MB_OK);
+ //MessageBox(NULL, qtjava_path, "QTJAVA after strcat", MB_OK);
+ } else {
+ qtjava_path[0] = 0; // not a valid path
+ }
+ //} else {
+ //MessageBox(NULL, "no qtjava set", "mess", MB_OK);
+ }
+
+ if (qtjava_path[0] == 0) { // not set yet
+ //if (getenv("WINDIR") == NULL) {
+ // uh-oh.. serious problem.. gonna have to report this
+ // but hopefully WINDIR is set on win98 too
+ //} else {
+
+ strcpy(qtjava_path, getenv("WINDIR"));
+ strcat(qtjava_path, "\\SYSTEM32\\QTJava.zip");
+
+ FILE *fp = fopen(qtjava_path, "rb");
+ if (fp != NULL) {
+ fclose(fp); // found it, all set
+ strcat(qtjava_path, ";"); // add path separator
+ //MessageBox(NULL, "found 2", "msg", MB_OK);
+ } else {
+ qtjava_path[0] = 0; // not a valid path
+ }
+ }
+
+ if (qtjava_path[0] == 0) {
+ strcpy(qtjava_path, getenv("WINDIR"));
+ strcat(qtjava_path, "\\SYSTEM\\QTJava.zip");
+
+ fp = fopen(qtjava_path, "rb");
+ if (fp != NULL) {
+ fclose(fp); // found it, all set
+ strcat(qtjava_path, ";"); // add path separator
+ //MessageBox(NULL, "found 3", "msg", MB_OK);
+ } else {
+ // doesn't seem to be installed, which is a problem.
+ // but the error will be reported by the pde
+ qtjava_path[0] = 0;
+ }
+ }
+
+ // don't put quotes around contents of cp, even though %s might have
+ // spaces in it. don't put quotes in it, because it's setting the
+ // environment variable for CLASSPATH, not being included on the
+ // command line. so setting the env var it's ok to have spaces,
+ // and the quotes prevent javax.comm.properties from being found.
+
+ strcpy(cp, app_classpath);
+ if (local_jre_installed) {
+ char *local_jre = mallocChars(64 + strlen(exe_directory) * 2);
+ sprintf(local_jre, "%s\\java\\lib\\rt.jar;%s\\java\\lib\\tools.jar;", exe_directory, exe_directory);
+ strcat(cp, local_jre);
+ }
+ strcat(cp, qtjava_path);
+
+ char *clean_cp = scrubPath(cp);
+ //if (!SetEnvironmentVariable("CLASSPATH", cp)) {
+ if (!SetEnvironmentVariable("CLASSPATH", clean_cp)) {
+ MessageBox(NULL, "Could not set CLASSPATH environment variable",
+ "Processing Error", MB_OK);
+ return 0;
+ }
+
+ //MessageBox(NULL, "2", "checking", MB_OK);
+
+ //char *env_path = (char *)malloc(strlen(getenv("PATH")) * sizeof(char));
+
+ int env_path_length = strlen(getenv("PATH"));
+ char *env_path = mallocChars(env_path_length);
+ strcpy(env_path, getenv("PATH"));
+ char *clean_path;
+
+ // need to add the local jre to the path for 'java mode' in the env
+ if (local_jre_installed) {
+ char *path_to_clean =
+ mallocChars(env_path_length + strlen(exe_directory) + 30);
+ sprintf(path_to_clean, "%s\\java\\bin;%s", exe_directory, env_path);
+ clean_path = scrubPath(path_to_clean);
+ } else {
+ clean_path = scrubPath(getenv("PATH"));
+ }
+
+ //MessageBox(NULL, clean_path, "after scrubbing PATH", MB_OK);
+ //MessageBox(NULL, "3", "checking", MB_OK);
+
+ if (!SetEnvironmentVariable("PATH", clean_path)) {
+ MessageBox(NULL, "Could not set PATH environment variable",
+ "Processing Error", MB_OK);
+ return 0;
+ }
+
+ // what gets put together to pass to jre
+ char *outgoing_cmd_line = (char *)malloc(16384 * sizeof(char));
+
+ // prepend the args for -mx and -ms
+ strcpy(outgoing_cmd_line, java_args);
+ strcat(outgoing_cmd_line, " ");
+
+ // add the name of the class to execute and a space before the next arg
+ strcat(outgoing_cmd_line, java_main_class);
+ strcat(outgoing_cmd_line, " ");
+
+ // append additional incoming stuff (document names), if any
+ strcat(outgoing_cmd_line, incoming_cmd_line);
+
+ //MessageBox(NULL, outgoing_cmd_line, "cmd_line", MB_OK);
+
+ char *executable =
+ (char *)malloc((strlen(exe_directory) + 256) * sizeof(char));
+ // exe_directory is the name path to the current application
+
+ if (local_jre_installed) {
+ strcpy(executable, exe_directory);
+ // copy in the path for javaw, relative to launcher.exe
+ strcat(executable, "\\java\\bin\\javaw.exe");
+ } else {
+ strcpy(executable, "javaw.exe");
+ }
+
+ SHELLEXECUTEINFO ShExecInfo;
+
+ // set up the execution info
+ ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
+ ShExecInfo.fMask = 0;
+ ShExecInfo.hwnd = 0;
+ ShExecInfo.lpVerb = "open";
+ ShExecInfo.lpFile = executable;
+ ShExecInfo.lpParameters = outgoing_cmd_line;
+ ShExecInfo.lpDirectory = exe_directory;
+ ShExecInfo.nShow = SW_SHOWNORMAL;
+ ShExecInfo.hInstApp = NULL;
+
+ if (!ShellExecuteEx(&ShExecInfo)) {
+ MessageBox(NULL, "Error calling ShellExecuteEx()",
+ "Processing Error", MB_OK);
+ return 0;
+ }
+
+ if (reinterpret_cast(ShExecInfo.hInstApp) <= 32) {
+
+ // some type of error occurred
+ switch (reinterpret_cast(ShExecInfo.hInstApp)) {
+ case ERROR_FILE_NOT_FOUND:
+ case ERROR_PATH_NOT_FOUND:
+ MessageBox(NULL, "A required file could not be found. \n"
+ "You may need to install a Java runtime\n"
+ "or re-install Processing.",
+ "Processing Error", MB_OK);
+ break;
+ case 0:
+ case SE_ERR_OOM:
+ MessageBox(NULL, "Not enough memory or resources to run at"
+ " this time.", "Processing Error", MB_OK);
+
+ break;
+ default:
+ MessageBox(NULL, "There is a problem with your installation.\n"
+ "If the problem persists, re-install the program.",
+ "Processing Error", MB_OK);
+ break;
+ }
+ }
+ return 0;
+}
+
+
+void removeLineEndings(char *what) {
+ int index = strlen(what) - 1;
+ while (index >= 0) {
+ if ((what[index] == 10) || (what[index] == 13)) {
+ what[index] = 0;
+ --index;
+ } else {
+ return;
+ }
+ }
+}
+
+
+// take a PATH environment variable, split on semicolons,
+// remove extraneous quotes, perhaps even make 8.3 syntax if necessary
+char *scrubPath(char *incoming) {
+ char *cleaned = mallocChars(strlen(incoming) * 2);
+
+ int found_so_far = 0;
+ char *p = (char*) strtok(incoming, ";");
+ while (p != NULL) {
+ char entry[1024];
+ /*
+ if (*p == '\"') {
+ // if this segment of the path contains quotes, remove them
+ int fixed_length = strlen(p) - 2;
+ strncpy(entry, &p[1], fixed_length);
+ entry[fixed_length] = 0;
+ //MessageBox(NULL, entry, "clipped", MB_OK);
+
+ // if it doesn't actually end with a quote, then the person
+ // is screwed anyway.. they can deal with that themselves
+ } else {
+ strcpy(entry, p);
+ }
+ */
+ strcpy(entry, p);
+ removeQuotes(entry);
+ // a trailing slash will cause FindFirstFile to fail.. grr [0109]
+ removeTrailingSlash(entry);
+ //MessageBox(NULL, entry, "entry", MB_OK);
+
+ // if this path doesn't exist, don't add it
+ WIN32_FIND_DATA find_file_data;
+ HANDLE hfind = FindFirstFile(entry, &find_file_data);
+ if (hfind != INVALID_HANDLE_VALUE) {
+ if (found_so_far) strcat(cleaned, ";");
+ strcat(cleaned, entry);
+ //MessageBox(NULL, cleaned, "cleaned so far", MB_OK);
+ FindClose(hfind);
+ found_so_far = 1;
+ //} else {
+ //MessageBox(NULL, entry, "removing", MB_OK);
+ }
+ // grab the next entry
+ p = (char*) strtok(NULL, ";");
+ }
+ //MessageBox(NULL, cleaned, "scrubPath", MB_OK);
+ return cleaned;
+}
+
+
+// eventually make this handle unicode
+char *mallocChars(int count) {
+ // add one for the terminator
+ char *outgoing = (char*) malloc(count * sizeof(char) + 1);
+ outgoing[0] = 0; // for safety
+ return outgoing;
+}
+
+
+void removeQuotes(char *quoted) {
+ int len = strlen(quoted);
+ // remove quote at the front
+ if (quoted[0] == '\"') {
+ for (int i = 0; i < len - 1; i++) {
+ quoted[i] = quoted[i+1];
+ }
+ len--;
+ quoted[len] = 0;
+ }
+ // remove quote at the end
+ if (len > 1) {
+ if (quoted[len - 1] == '\"') {
+ len--;
+ quoted[len] = 0;
+ }
+ }
+}
+
+
+void removeTrailingSlash(char *slashed) {
+ int len = strlen(slashed);
+ if (len > 1) {
+ if (slashed[len - 1] == '\\') {
+ len--;
+ slashed[len] = 0;
+ }
+ }
+}
diff --git a/build/windows/jre.zip b/build/windows/jre.zip
new file mode 100644
index 000000000..a9522ec68
Binary files /dev/null and b/build/windows/jre.zip differ
diff --git a/build/windows/launcher/about.bmp b/build/windows/launcher/about.bmp
new file mode 100755
index 000000000..355293746
Binary files /dev/null and b/build/windows/launcher/about.bmp differ
diff --git a/build/windows/launcher/application.ico b/build/windows/launcher/application.ico
new file mode 100644
index 000000000..6989af611
Binary files /dev/null and b/build/windows/launcher/application.ico differ
diff --git a/build/windows/launcher/config.xml b/build/windows/launcher/config.xml
new file mode 100755
index 000000000..a33138186
--- /dev/null
+++ b/build/windows/launcher/config.xml
@@ -0,0 +1,44 @@
+
+ true
+ gui
+ lib
+ processing.exe
+
+
+ .
+ normal
+ http://java.sun.com/javase/downloads/
+
+ false
+ false
+
+ application.ico
+
+ processing.app.Base
+ lib/pde.jar
+ lib/core.jar
+ lib/jna.jar
+ lib/ecj.jar
+ lib/antlr.jar
+
+
+ java
+ 1.5.0
+
+ jdkOnly
+ -Xms128m -Xmx128m
+
+
+ about.bmp
+ true
+ 60
+ true
+
+
+ An error occurred while starting the application.
+ This application was configured to use a bundled Java Runtime Environment but the runtime is missing or corrupted.
+ This application requires at least Java Development Kit
+ The registry refers to a nonexistent Java Development Kit installation or the runtime is corrupted.
+ An application instance is already running.
+
+
diff --git a/build/windows/launcher/launch4j/.classpath b/build/windows/launcher/launch4j/.classpath
new file mode 100755
index 000000000..734d175a6
--- /dev/null
+++ b/build/windows/launcher/launch4j/.classpath
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/build/windows/launcher/launch4j/.project b/build/windows/launcher/launch4j/.project
new file mode 100755
index 000000000..1c1309dfa
--- /dev/null
+++ b/build/windows/launcher/launch4j/.project
@@ -0,0 +1,17 @@
+
+
+ launch4j
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/build/windows/launcher/launch4j/.settings/org.eclipse.jdt.core.prefs b/build/windows/launcher/launch4j/.settings/org.eclipse.jdt.core.prefs
new file mode 100755
index 000000000..056498058
--- /dev/null
+++ b/build/windows/launcher/launch4j/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,12 @@
+#Sun Jul 20 14:10:30 CEST 2008
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.4
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.4
+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.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=warning
+org.eclipse.jdt.core.compiler.source=1.4
diff --git a/build/windows/launcher/launch4j/LICENSE.txt b/build/windows/launcher/launch4j/LICENSE.txt
new file mode 100755
index 000000000..82223322f
--- /dev/null
+++ b/build/windows/launcher/launch4j/LICENSE.txt
@@ -0,0 +1,30 @@
+Launch4j (http://launch4j.sourceforge.net/)
+Cross-platform Java application wrapper for creating Windows native executables.
+
+Copyright (c) 2004, 2008 Grzegorz Kowal
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
diff --git a/build/windows/launcher/launch4j/bin/COPYING b/build/windows/launcher/launch4j/bin/COPYING
new file mode 100755
index 000000000..60549be51
--- /dev/null
+++ b/build/windows/launcher/launch4j/bin/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C) 19yy
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ , 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/build/windows/launcher/launch4j/bin/ld.exe b/build/windows/launcher/launch4j/bin/ld.exe
new file mode 100755
index 000000000..f388b9513
Binary files /dev/null and b/build/windows/launcher/launch4j/bin/ld.exe differ
diff --git a/build/windows/launcher/launch4j/bin/windres.exe b/build/windows/launcher/launch4j/bin/windres.exe
new file mode 100755
index 000000000..4ad2ae98a
Binary files /dev/null and b/build/windows/launcher/launch4j/bin/windres.exe differ
diff --git a/build/windows/launcher/launch4j/build.xml b/build/windows/launcher/launch4j/build.xml
new file mode 100755
index 000000000..a7682ce0c
--- /dev/null
+++ b/build/windows/launcher/launch4j/build.xml
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/build/windows/launcher/launch4j/demo/ConsoleApp/ConsoleApp.exe b/build/windows/launcher/launch4j/demo/ConsoleApp/ConsoleApp.exe
new file mode 100755
index 000000000..d8a8f75d0
Binary files /dev/null and b/build/windows/launcher/launch4j/demo/ConsoleApp/ConsoleApp.exe differ
diff --git a/build/windows/launcher/launch4j/demo/ConsoleApp/ConsoleApp.jar b/build/windows/launcher/launch4j/demo/ConsoleApp/ConsoleApp.jar
new file mode 100755
index 000000000..6d4b126e6
Binary files /dev/null and b/build/windows/launcher/launch4j/demo/ConsoleApp/ConsoleApp.jar differ
diff --git a/build/windows/launcher/launch4j/demo/ConsoleApp/build.bat b/build/windows/launcher/launch4j/demo/ConsoleApp/build.bat
new file mode 100755
index 000000000..ed5f704e3
--- /dev/null
+++ b/build/windows/launcher/launch4j/demo/ConsoleApp/build.bat
@@ -0,0 +1,14 @@
+@echo off
+if "%ANT_HOME%"=="" goto noAntHome
+if "%JAVA_HOME%"=="" goto noJavaHome
+call "%ANT_HOME%\bin\ant.bat" exe
+goto end
+
+:noAntHome
+echo ANT_HOME environment variable is not set
+goto end
+
+:noJavaHome
+echo JAVA_HOME environment variable is not set
+
+:end
diff --git a/build/windows/launcher/launch4j/demo/ConsoleApp/build.xml b/build/windows/launcher/launch4j/demo/ConsoleApp/build.xml
new file mode 100755
index 000000000..5f3473da6
--- /dev/null
+++ b/build/windows/launcher/launch4j/demo/ConsoleApp/build.xml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/build/windows/launcher/launch4j/demo/ConsoleApp/l4j/ConsoleApp.ico b/build/windows/launcher/launch4j/demo/ConsoleApp/l4j/ConsoleApp.ico
new file mode 100755
index 000000000..cc4c540e2
Binary files /dev/null and b/build/windows/launcher/launch4j/demo/ConsoleApp/l4j/ConsoleApp.ico differ
diff --git a/build/windows/launcher/launch4j/demo/ConsoleApp/lib/readme.txt b/build/windows/launcher/launch4j/demo/ConsoleApp/lib/readme.txt
new file mode 100755
index 000000000..ef44ded3a
--- /dev/null
+++ b/build/windows/launcher/launch4j/demo/ConsoleApp/lib/readme.txt
@@ -0,0 +1,8 @@
+Put your jar libs here and the build script will include them
+in the classpath stored inside the jar manifest.
+In order to run your application move the output exe file from
+the dist directory to the same level as lib.
+
+SimpleApp.exe
+lib/
+lib/xml.jar
diff --git a/build/windows/launcher/launch4j/demo/ConsoleApp/readme.txt b/build/windows/launcher/launch4j/demo/ConsoleApp/readme.txt
new file mode 100755
index 000000000..fa38dc8bd
--- /dev/null
+++ b/build/windows/launcher/launch4j/demo/ConsoleApp/readme.txt
@@ -0,0 +1 @@
+To build the example application set JAVA_HOME and ANT_HOME environment variables.
diff --git a/build/windows/launcher/launch4j/demo/ConsoleApp/src/net/sf/launch4j/example/ConsoleApp.java b/build/windows/launcher/launch4j/demo/ConsoleApp/src/net/sf/launch4j/example/ConsoleApp.java
new file mode 100755
index 000000000..eb1398c2c
--- /dev/null
+++ b/build/windows/launcher/launch4j/demo/ConsoleApp/src/net/sf/launch4j/example/ConsoleApp.java
@@ -0,0 +1,72 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package net.sf.launch4j.example;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+
+/**
+ * @author Copyright (C) 2005 Grzegorz Kowal
+ */
+public class ConsoleApp {
+ public static void main(String[] args) {
+ StringBuffer sb = new StringBuffer("Hello World!\n\nJava version: ");
+ sb.append(System.getProperty("java.version"));
+ sb.append("\nJava home: ");
+ sb.append(System.getProperty("java.home"));
+ sb.append("\nCurrent dir: ");
+ sb.append(System.getProperty("user.dir"));
+ if (args.length > 0) {
+ sb.append("\nArgs: ");
+ for (int i = 0; i < args.length; i++) {
+ sb.append(args[i]);
+ sb.append(' ');
+ }
+ }
+ sb.append("\n\nEnter a line of text, Ctrl-C to stop.\n\n>");
+ System.out.print(sb.toString());
+ try {
+ BufferedReader is = new BufferedReader(new InputStreamReader(System.in));
+ String line;
+ while ((line = is.readLine()) != null && !line.equalsIgnoreCase("quit")) {
+ System.out.print("You wrote: " + line + "\n\n>");
+ }
+ is.close();
+ System.exit(123);
+ } catch (IOException e) {
+ System.err.print(e);
+ }
+ }
+}
diff --git a/build/windows/launcher/launch4j/demo/LICENSE.txt b/build/windows/launcher/launch4j/demo/LICENSE.txt
new file mode 100755
index 000000000..d6d6bb5ea
--- /dev/null
+++ b/build/windows/launcher/launch4j/demo/LICENSE.txt
@@ -0,0 +1,30 @@
+Launch4j (http://launch4j.sourceforge.net/)
+Cross-platform Java application wrapper for creating Windows native executables.
+
+Copyright (c) 2004, 2007 Grzegorz Kowal
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
diff --git a/build/windows/launcher/launch4j/demo/SimpleApp/SimpleApp.exe b/build/windows/launcher/launch4j/demo/SimpleApp/SimpleApp.exe
new file mode 100755
index 000000000..1a75fc298
Binary files /dev/null and b/build/windows/launcher/launch4j/demo/SimpleApp/SimpleApp.exe differ
diff --git a/build/windows/launcher/launch4j/demo/SimpleApp/SimpleApp.jar b/build/windows/launcher/launch4j/demo/SimpleApp/SimpleApp.jar
new file mode 100755
index 000000000..f02c6133b
Binary files /dev/null and b/build/windows/launcher/launch4j/demo/SimpleApp/SimpleApp.jar differ
diff --git a/build/windows/launcher/launch4j/demo/SimpleApp/build.bat b/build/windows/launcher/launch4j/demo/SimpleApp/build.bat
new file mode 100755
index 000000000..ed5f704e3
--- /dev/null
+++ b/build/windows/launcher/launch4j/demo/SimpleApp/build.bat
@@ -0,0 +1,14 @@
+@echo off
+if "%ANT_HOME%"=="" goto noAntHome
+if "%JAVA_HOME%"=="" goto noJavaHome
+call "%ANT_HOME%\bin\ant.bat" exe
+goto end
+
+:noAntHome
+echo ANT_HOME environment variable is not set
+goto end
+
+:noJavaHome
+echo JAVA_HOME environment variable is not set
+
+:end
diff --git a/build/windows/launcher/launch4j/demo/SimpleApp/build.xml b/build/windows/launcher/launch4j/demo/SimpleApp/build.xml
new file mode 100755
index 000000000..82f4b4998
--- /dev/null
+++ b/build/windows/launcher/launch4j/demo/SimpleApp/build.xml
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/build/windows/launcher/launch4j/demo/SimpleApp/l4j/SimpleApp.ico b/build/windows/launcher/launch4j/demo/SimpleApp/l4j/SimpleApp.ico
new file mode 100755
index 000000000..cc4c540e2
Binary files /dev/null and b/build/windows/launcher/launch4j/demo/SimpleApp/l4j/SimpleApp.ico differ
diff --git a/build/windows/launcher/launch4j/demo/SimpleApp/l4j/SimpleApp.xml b/build/windows/launcher/launch4j/demo/SimpleApp/l4j/SimpleApp.xml
new file mode 100755
index 000000000..9a7dc940a
--- /dev/null
+++ b/build/windows/launcher/launch4j/demo/SimpleApp/l4j/SimpleApp.xml
@@ -0,0 +1,18 @@
+
+ gui
+ ../SimpleApp.jar
+ ../SimpleApp.exe
+ SimpleApp
+ .
+ true
+ SimpleApp.ico
+
+ 1.4.0
+
+
+ splash.bmp
+ true
+ 60
+ true
+
+
\ No newline at end of file
diff --git a/build/windows/launcher/launch4j/demo/SimpleApp/l4j/splash.bmp b/build/windows/launcher/launch4j/demo/SimpleApp/l4j/splash.bmp
new file mode 100755
index 000000000..88d7bbf10
Binary files /dev/null and b/build/windows/launcher/launch4j/demo/SimpleApp/l4j/splash.bmp differ
diff --git a/build/windows/launcher/launch4j/demo/SimpleApp/lib/readme.txt b/build/windows/launcher/launch4j/demo/SimpleApp/lib/readme.txt
new file mode 100755
index 000000000..ef44ded3a
--- /dev/null
+++ b/build/windows/launcher/launch4j/demo/SimpleApp/lib/readme.txt
@@ -0,0 +1,8 @@
+Put your jar libs here and the build script will include them
+in the classpath stored inside the jar manifest.
+In order to run your application move the output exe file from
+the dist directory to the same level as lib.
+
+SimpleApp.exe
+lib/
+lib/xml.jar
diff --git a/build/windows/launcher/launch4j/demo/SimpleApp/readme.txt b/build/windows/launcher/launch4j/demo/SimpleApp/readme.txt
new file mode 100755
index 000000000..fa38dc8bd
--- /dev/null
+++ b/build/windows/launcher/launch4j/demo/SimpleApp/readme.txt
@@ -0,0 +1 @@
+To build the example application set JAVA_HOME and ANT_HOME environment variables.
diff --git a/build/windows/launcher/launch4j/demo/SimpleApp/src/net/sf/launch4j/example/SimpleApp.java b/build/windows/launcher/launch4j/demo/SimpleApp/src/net/sf/launch4j/example/SimpleApp.java
new file mode 100755
index 000000000..8e87c5953
--- /dev/null
+++ b/build/windows/launcher/launch4j/demo/SimpleApp/src/net/sf/launch4j/example/SimpleApp.java
@@ -0,0 +1,104 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package net.sf.launch4j.example;
+
+import java.awt.Dimension;
+import java.awt.Toolkit;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+
+import javax.swing.JFrame;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.UIManager;
+
+public class SimpleApp extends JFrame {
+ public SimpleApp(String[] args) {
+ super("Java Application");
+ final int inset = 100;
+ Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
+ setBounds (inset, inset,
+ screenSize.width - inset * 2, screenSize.height - inset * 2);
+
+ JMenu menu = new JMenu("File");
+ menu.add(new JMenuItem("Open"));
+ menu.add(new JMenuItem("Save"));
+ JMenuBar mb = new JMenuBar();
+ mb.setOpaque(true);
+ mb.add(menu);
+ setJMenuBar(mb);
+
+ this.addWindowListener(new WindowAdapter() {
+ public void windowClosing(WindowEvent e) {
+ System.exit(123);
+ }});
+ setVisible(true);
+
+ StringBuffer sb = new StringBuffer("Java version: ");
+ sb.append(System.getProperty("java.version"));
+ sb.append("\nJava home: ");
+ sb.append(System.getProperty("java.home"));
+ sb.append("\nCurrent dir: ");
+ sb.append(System.getProperty("user.dir"));
+ if (args.length > 0) {
+ sb.append("\nArgs: ");
+ for (int i = 0; i < args.length; i++) {
+ sb.append(args[i]);
+ sb.append(' ');
+ }
+ }
+ JOptionPane.showMessageDialog(this,
+ sb.toString(),
+ "Info",
+ JOptionPane.INFORMATION_MESSAGE);
+ }
+
+ public static void setLAF() {
+ JFrame.setDefaultLookAndFeelDecorated(true);
+ Toolkit.getDefaultToolkit().setDynamicLayout(true);
+ System.setProperty("sun.awt.noerasebackground","true");
+ try {
+ UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
+ } catch (Exception e) {
+ System.err.println("Failed to set LookAndFeel");
+ }
+ }
+
+ public static void main(String[] args) {
+ setLAF();
+ new SimpleApp(args);
+ }
+}
diff --git a/build/windows/launcher/launch4j/demo/readme.txt b/build/windows/launcher/launch4j/demo/readme.txt
new file mode 100755
index 000000000..f59178214
--- /dev/null
+++ b/build/windows/launcher/launch4j/demo/readme.txt
@@ -0,0 +1,3 @@
+JRE/SDK 1.4.0 or higher must be installed on your system to run this demo.
+
+try running it with some command line arguments...
diff --git a/build/windows/launcher/launch4j/head/LICENSE.txt b/build/windows/launcher/launch4j/head/LICENSE.txt
new file mode 100755
index 000000000..536488e61
--- /dev/null
+++ b/build/windows/launcher/launch4j/head/LICENSE.txt
@@ -0,0 +1,23 @@
+Copyright (c) 2004, 2007 Grzegorz Kowal
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+Except as contained in this notice, the name(s) of the above copyright holders
+shall not be used in advertising or otherwise to promote the sale, use or other
+dealings in this Software without prior written authorization.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
\ No newline at end of file
diff --git a/build/windows/launcher/launch4j/head_src/LICENSE.txt b/build/windows/launcher/launch4j/head_src/LICENSE.txt
new file mode 100755
index 000000000..2805f412a
--- /dev/null
+++ b/build/windows/launcher/launch4j/head_src/LICENSE.txt
@@ -0,0 +1,23 @@
+Copyright (c) 2004, 2008 Grzegorz Kowal
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+Except as contained in this notice, the name(s) of the above copyright holders
+shall not be used in advertising or otherwise to promote the sale, use or other
+dealings in this Software without prior written authorization.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/build/windows/launcher/launch4j/head_src/consolehead/Makefile.win b/build/windows/launcher/launch4j/head_src/consolehead/Makefile.win
new file mode 100755
index 000000000..349e4c00f
--- /dev/null
+++ b/build/windows/launcher/launch4j/head_src/consolehead/Makefile.win
@@ -0,0 +1,33 @@
+# Project: consolehead
+# Makefile created by Dev-C++ 4.9.9.2
+
+CPP = g++.exe
+CC = gcc.exe
+WINDRES = windres.exe
+RES =
+OBJ = ../../head/consolehead.o ../../head/head.o $(RES)
+LINKOBJ = ../../head/consolehead.o ../../head/head.o $(RES)
+LIBS = -L"C:/Dev-Cpp/lib" -n -s
+INCS = -I"C:/Dev-Cpp/include"
+CXXINCS = -I"C:/Dev-Cpp/lib/gcc/mingw32/3.4.2/include" -I"C:/Dev-Cpp/include/c++/3.4.2/backward" -I"C:/Dev-Cpp/include/c++/3.4.2/mingw32" -I"C:/Dev-Cpp/include/c++/3.4.2" -I"C:/Dev-Cpp/include"
+BIN = consolehead.exe
+CXXFLAGS = $(CXXINCS) -fexpensive-optimizations -O3
+CFLAGS = $(INCS) -fexpensive-optimizations -O3
+RM = rm -f
+
+.PHONY: all all-before all-after clean clean-custom
+
+all: all-before consolehead.exe all-after
+
+
+clean: clean-custom
+ ${RM} $(OBJ) $(BIN)
+
+$(BIN): $(OBJ)
+# $(CC) $(LINKOBJ) -o "consolehead.exe" $(LIBS)
+
+../../head/consolehead.o: consolehead.c
+ $(CC) -c consolehead.c -o ../../head/consolehead.o $(CFLAGS)
+
+../../head/head.o: ../head.c
+ $(CC) -c ../head.c -o ../../head/head.o $(CFLAGS)
diff --git a/build/windows/launcher/launch4j/head_src/consolehead/consolehead.c b/build/windows/launcher/launch4j/head_src/consolehead/consolehead.c
new file mode 100755
index 000000000..755a7673c
--- /dev/null
+++ b/build/windows/launcher/launch4j/head_src/consolehead/consolehead.c
@@ -0,0 +1,65 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ Except as contained in this notice, the name(s) of the above copyright holders
+ shall not be used in advertising or otherwise to promote the sale, use or other
+ dealings in this Software without prior written authorization.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#include "../resource.h"
+#include "../head.h"
+
+int main(int argc, char* argv[])
+{
+ setConsoleFlag();
+ LPTSTR cmdLine = GetCommandLine();
+ if (*cmdLine == '"') {
+ if (*(cmdLine = strchr(cmdLine + 1, '"') + 1)) {
+ cmdLine++;
+ }
+ } else if ((cmdLine = strchr(cmdLine, ' ')) != NULL) {
+ cmdLine++;
+ } else {
+ cmdLine = "";
+ }
+ int result = prepare(cmdLine);
+ if (result == ERROR_ALREADY_EXISTS) {
+ char errMsg[BIG_STR] = {0};
+ loadString(INSTANCE_ALREADY_EXISTS_MSG, errMsg);
+ msgBox(errMsg);
+ closeLogFile();
+ return 2;
+ }
+ if (result != TRUE) {
+ signalError();
+ return 1;
+ }
+
+ result = (int) execute(TRUE);
+ if (result == -1) {
+ signalError();
+ } else {
+ return result;
+ }
+}
diff --git a/build/windows/launcher/launch4j/head_src/consolehead/consolehead.dev b/build/windows/launcher/launch4j/head_src/consolehead/consolehead.dev
new file mode 100755
index 000000000..a309ec94f
--- /dev/null
+++ b/build/windows/launcher/launch4j/head_src/consolehead/consolehead.dev
@@ -0,0 +1,108 @@
+[Project]
+FileName=consolehead.dev
+Name=consolehead
+UnitCount=4
+Type=1
+Ver=1
+ObjFiles=
+Includes=
+Libs=
+PrivateResource=
+ResourceIncludes=
+MakeIncludes=
+Compiler=
+CppCompiler=
+Linker=-n_@@_
+IsCpp=0
+Icon=
+ExeOutput=
+ObjectOutput=..\..\head
+OverrideOutput=0
+OverrideOutputName=consolehead.exe
+HostApplication=
+Folders=
+CommandLine=
+UseCustomMakefile=0
+CustomMakefile=Makefile.win
+IncludeVersionInfo=0
+SupportXPThemes=0
+CompilerSet=0
+CompilerSettings=0000000001001000000100
+
+[Unit1]
+FileName=consolehead.c
+CompileCpp=0
+Folder=consolehead
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[VersionInfo]
+Major=0
+Minor=1
+Release=1
+Build=1
+LanguageID=1033
+CharsetID=1252
+CompanyName=
+FileVersion=
+FileDescription=Developed using the Dev-C++ IDE
+InternalName=
+LegalCopyright=
+LegalTrademarks=
+OriginalFilename=
+ProductName=
+ProductVersion=
+AutoIncBuildNr=0
+
+[Unit2]
+FileName=..\resource.h
+CompileCpp=0
+Folder=consolehead
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit3]
+FileName=..\head.c
+CompileCpp=0
+Folder=consolehead
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit4]
+FileName=..\head.h
+CompileCpp=0
+Folder=consolehead
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit5]
+FileName=..\head.rc
+Folder=consolehead
+Compile=1
+Link=0
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit6]
+FileName=..\resid.h
+CompileCpp=0
+Folder=consolehead
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
diff --git a/build/windows/launcher/launch4j/head_src/guihead/Makefile.win b/build/windows/launcher/launch4j/head_src/guihead/Makefile.win
new file mode 100755
index 000000000..3c642f8fc
--- /dev/null
+++ b/build/windows/launcher/launch4j/head_src/guihead/Makefile.win
@@ -0,0 +1,38 @@
+# Project: guihead
+# Makefile created by Dev-C++ 4.9.9.2
+
+CPP = g++.exe
+CC = gcc.exe
+WINDRES = windres.exe
+RES =
+OBJ = ../../head/guihead.o ../../head/head.o $(RES)
+LINKOBJ = ../../head/guihead.o ../../head/head.o $(RES)
+
+# removed dev-cpp flags, replacing for cygwin/mingw [fry]
+CXXFLAGS = -mwindows -mno-cygwin -O2 -Wall
+CFLAGS = -mwindows -mno-cygwin -O2 -Wall
+#CFLAGS = -I/cygdrive/c/cygwin/usr/include/mingw
+#LIBS = -L"C:/Dev-Cpp/lib" -mwindows -n -s
+#INCS = -I"C:/Dev-Cpp/include"
+#CXXINCS = -I"C:/Dev-Cpp/lib/gcc/mingw32/3.4.2/include" -I"C:/Dev-Cpp/include/c++/3.4.2/backward" -I"C:/Dev-Cpp/include/c++/3.4.2/mingw32" -I"C:/Dev-Cpp/include/c++/3.4.2" -I"C:/Dev-Cpp/include"
+BIN = guihead.exe
+#CXXFLAGS = $(CXXINCS) -fexpensive-optimizations -O3
+#CFLAGS = $(INCS) -fexpensive-optimizations -O3
+RM = rm -f
+
+.PHONY: all all-before all-after clean clean-custom
+
+all: all-before guihead.exe all-after
+
+
+clean: clean-custom
+ ${RM} $(OBJ) $(BIN)
+
+$(BIN): $(OBJ)
+# $(CC) $(LINKOBJ) -o "guihead.exe" $(LIBS)
+
+../../head/guihead.o: guihead.c
+ $(CC) -c guihead.c -o ../../head/guihead.o $(CFLAGS)
+
+../../head/head.o: ../head.c
+ $(CC) -c ../head.c -o ../../head/head.o $(CFLAGS)
diff --git a/build/windows/launcher/launch4j/head_src/guihead/guihead.c b/build/windows/launcher/launch4j/head_src/guihead/guihead.c
new file mode 100755
index 000000000..508a5bdac
--- /dev/null
+++ b/build/windows/launcher/launch4j/head_src/guihead/guihead.c
@@ -0,0 +1,185 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+ Sylvain Mina (single instance patch)
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ Except as contained in this notice, the name(s) of the above copyright holders
+ shall not be used in advertising or otherwise to promote the sale, use or other
+ dealings in this Software without prior written authorization.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#include "../resource.h"
+#include "../head.h"
+#include "guihead.h"
+
+extern FILE* hLog;
+extern PROCESS_INFORMATION pi;
+
+HWND hWnd;
+DWORD dwExitCode = 0;
+BOOL stayAlive = FALSE;
+BOOL splash = FALSE;
+BOOL splashTimeoutErr;
+BOOL waitForWindow;
+int splashTimeout = DEFAULT_SPLASH_TIMEOUT;
+
+int APIENTRY WinMain(HINSTANCE hInstance,
+ HINSTANCE hPrevInstance,
+ LPSTR lpCmdLine,
+ int nCmdShow) {
+ int result = prepare(lpCmdLine);
+ if (result == ERROR_ALREADY_EXISTS) {
+ HWND handle = getInstanceWindow();
+ ShowWindow(handle, SW_SHOW);
+ SetForegroundWindow(handle);
+ closeLogFile();
+ return 2;
+ }
+ if (result != TRUE) {
+ signalError();
+ return 1;
+ }
+
+ splash = loadBool(SHOW_SPLASH)
+ && strstr(lpCmdLine, "--l4j-no-splash") == NULL;
+ stayAlive = loadBool(GUI_HEADER_STAYS_ALIVE)
+ && strstr(lpCmdLine, "--l4j-dont-wait") == NULL;
+ if (splash || stayAlive) {
+ hWnd = CreateWindowEx(WS_EX_TOOLWINDOW, "STATIC", "",
+ WS_POPUP | SS_BITMAP,
+ 0, 0, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
+ if (splash) {
+ char timeout[10] = {0};
+ if (loadString(SPLASH_TIMEOUT, timeout)) {
+ splashTimeout = atoi(timeout);
+ if (splashTimeout <= 0 || splashTimeout > MAX_SPLASH_TIMEOUT) {
+ splashTimeout = DEFAULT_SPLASH_TIMEOUT;
+ }
+ }
+ splashTimeoutErr = loadBool(SPLASH_TIMEOUT_ERR)
+ && strstr(lpCmdLine, "--l4j-no-splash-err") == NULL;
+ waitForWindow = loadBool(SPLASH_WAITS_FOR_WINDOW);
+ HANDLE hImage = LoadImage(hInstance, // handle of the instance containing the image
+ MAKEINTRESOURCE(SPLASH_BITMAP), // name or identifier of image
+ IMAGE_BITMAP, // type of image
+ 0, // desired width
+ 0, // desired height
+ LR_DEFAULTSIZE);
+ if (hImage == NULL) {
+ signalError();
+ return 1;
+ }
+ SendMessage(hWnd, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM) hImage);
+ RECT rect;
+ GetWindowRect(hWnd, &rect);
+ int x = (GetSystemMetrics(SM_CXSCREEN) - (rect.right - rect.left)) / 2;
+ int y = (GetSystemMetrics(SM_CYSCREEN) - (rect.bottom - rect.top)) / 2;
+ SetWindowPos(hWnd, HWND_TOP, x, y, 0, 0, SWP_NOSIZE);
+ ShowWindow(hWnd, nCmdShow);
+ UpdateWindow (hWnd);
+ }
+ if (!SetTimer (hWnd, ID_TIMER, 1000 /* 1s */, TimerProc)) {
+ signalError();
+ return 1;
+ }
+ }
+ if (execute(FALSE) == -1) {
+ signalError();
+ return 1;
+ }
+ if (!(splash || stayAlive)) {
+ debug("Exit code:\t0\n");
+ closeHandles();
+ return 0;
+ }
+
+ MSG msg;
+ while (GetMessage(&msg, NULL, 0, 0)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ debug("Exit code:\t%d\n", dwExitCode);
+ closeHandles();
+ return dwExitCode;
+}
+
+HWND getInstanceWindow() {
+ char windowTitle[STR];
+ char instWindowTitle[STR] = {0};
+ if (loadString(INSTANCE_WINDOW_TITLE, instWindowTitle)) {
+ HWND handle = FindWindowEx(NULL, NULL, NULL, NULL);
+ while (handle != NULL) {
+ GetWindowText(handle, windowTitle, STR - 1);
+ if (strstr(windowTitle, instWindowTitle) != NULL) {
+ return handle;
+ } else {
+ handle = FindWindowEx(NULL, handle, NULL, NULL);
+ }
+ }
+ }
+ return NULL;
+}
+
+BOOL CALLBACK enumwndfn(HWND hwnd, LPARAM lParam) {
+ DWORD processId;
+ GetWindowThreadProcessId(hwnd, &processId);
+ if (pi.dwProcessId == processId) {
+ LONG styles = GetWindowLong(hwnd, GWL_STYLE);
+ if ((styles & WS_VISIBLE) != 0) {
+ splash = FALSE;
+ ShowWindow(hWnd, SW_HIDE);
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+VOID CALLBACK TimerProc(
+ HWND hwnd, // handle of window for timer messages
+ UINT uMsg, // WM_TIMER message
+ UINT idEvent, // timer identifier
+ DWORD dwTime) { // current system time
+
+ if (splash) {
+ if (splashTimeout == 0) {
+ splash = FALSE;
+ ShowWindow(hWnd, SW_HIDE);
+ if (waitForWindow && splashTimeoutErr) {
+ KillTimer(hwnd, ID_TIMER);
+ signalError();
+ PostQuitMessage(0);
+ }
+ } else {
+ splashTimeout--;
+ if (waitForWindow) {
+ EnumWindows(enumwndfn, 0);
+ }
+ }
+ }
+ GetExitCodeProcess(pi.hProcess, &dwExitCode);
+ if (dwExitCode != STILL_ACTIVE
+ || !(splash || stayAlive)) {
+ KillTimer(hWnd, ID_TIMER);
+ PostQuitMessage(0);
+ }
+}
diff --git a/build/windows/launcher/launch4j/head_src/guihead/guihead.dev b/build/windows/launcher/launch4j/head_src/guihead/guihead.dev
new file mode 100755
index 000000000..7c30088f1
--- /dev/null
+++ b/build/windows/launcher/launch4j/head_src/guihead/guihead.dev
@@ -0,0 +1,109 @@
+[Project]
+FileName=guihead.dev
+Name=guihead
+UnitCount=5
+Type=0
+Ver=1
+ObjFiles=
+Includes=
+Libs=
+PrivateResource=
+ResourceIncludes=
+MakeIncludes=
+Compiler=
+CppCompiler=
+Linker=-n_@@_
+IsCpp=0
+Icon=
+ExeOutput=
+ObjectOutput=..\..\head
+OverrideOutput=0
+OverrideOutputName=guihead.exe
+HostApplication=
+Folders=
+CommandLine=
+UseCustomMakefile=1
+CustomMakefile=Makefile.win
+IncludeVersionInfo=0
+SupportXPThemes=0
+CompilerSet=0
+CompilerSettings=0000000001001000000100
+
+[Unit1]
+FileName=guihead.c
+CompileCpp=0
+Folder=guihead
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=$(CC) -c guihead.c -o ../../head/guihead.o $(CFLAGS)
+
+[Unit2]
+FileName=guihead.h
+CompileCpp=0
+Folder=guihead
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[VersionInfo]
+Major=0
+Minor=1
+Release=1
+Build=1
+LanguageID=1033
+CharsetID=1252
+CompanyName=
+FileVersion=
+FileDescription=Developed using the Dev-C++ IDE
+InternalName=
+LegalCopyright=
+LegalTrademarks=
+OriginalFilename=
+ProductName=
+ProductVersion=
+AutoIncBuildNr=0
+
+[Unit4]
+FileName=..\head.h
+CompileCpp=0
+Folder=guihead
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit6]
+FileName=..\resid.h
+CompileCpp=0
+Folder=guihead
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit3]
+FileName=..\head.c
+CompileCpp=0
+Folder=guihead
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit5]
+FileName=..\resource.h
+CompileCpp=0
+Folder=guihead
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
diff --git a/build/windows/launcher/launch4j/head_src/guihead/guihead.h b/build/windows/launcher/launch4j/head_src/guihead/guihead.h
new file mode 100755
index 000000000..2fc71e31f
--- /dev/null
+++ b/build/windows/launcher/launch4j/head_src/guihead/guihead.h
@@ -0,0 +1,43 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ Except as contained in this notice, the name(s) of the above copyright holders
+ shall not be used in advertising or otherwise to promote the sale, use or other
+ dealings in this Software without prior written authorization.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#define ID_TIMER 1
+#define DEFAULT_SPLASH_TIMEOUT 60 /* 60 seconds */
+#define MAX_SPLASH_TIMEOUT 60 * 15 /* 15 minutes */
+
+HWND getInstanceWindow();
+
+BOOL CALLBACK enumwndfn(HWND hwnd, LPARAM lParam);
+
+VOID CALLBACK TimerProc(
+ HWND hwnd, // handle of window for timer messages
+ UINT uMsg, // WM_TIMER message
+ UINT idEvent, // timer identifier
+ DWORD dwTime // current system time
+);
diff --git a/build/windows/launcher/launch4j/head_src/head.c b/build/windows/launcher/launch4j/head_src/head.c
new file mode 100755
index 000000000..1ff937694
--- /dev/null
+++ b/build/windows/launcher/launch4j/head_src/head.c
@@ -0,0 +1,818 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2008 Grzegorz Kowal,
+ Ian Roberts (jdk preference patch)
+ Sylvain Mina (single instance patch)
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ Except as contained in this notice, the name(s) of the above copyright holders
+ shall not be used in advertising or otherwise to promote the sale, use or other
+ dealings in this Software without prior written authorization.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#include "resource.h"
+#include "head.h"
+
+HMODULE hModule;
+FILE* hLog;
+BOOL console = FALSE;
+BOOL wow64 = FALSE;
+int foundJava = NO_JAVA_FOUND;
+
+struct _stat statBuf;
+PROCESS_INFORMATION pi;
+DWORD priority;
+
+char mutexName[STR] = {0};
+
+char errUrl[256] = {0};
+char errTitle[STR] = "Launch4j";
+char errMsg[BIG_STR] = {0};
+
+char javaMinVer[STR] = {0};
+char javaMaxVer[STR] = {0};
+char foundJavaVer[STR] = {0};
+char foundJavaKey[_MAX_PATH] = {0};
+
+char oldPwd[_MAX_PATH] = {0};
+char workingDir[_MAX_PATH] = {0};
+char cmd[_MAX_PATH] = {0};
+char args[MAX_ARGS] = {0};
+
+FILE* openLogFile(const char* exePath, const int pathLen) {
+ char path[_MAX_PATH] = {0};
+ strncpy(path, exePath, pathLen);
+ strcat(path, "\\launch4j.log");
+ return fopen(path, "a");
+}
+
+void closeLogFile() {
+ if (hLog != NULL) {
+ fclose(hLog);
+ }
+}
+
+void setWow64Flag() {
+ LPFN_ISWOW64PROCESS fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(
+ GetModuleHandle(TEXT("kernel32")), "IsWow64Process");
+
+ if (fnIsWow64Process != NULL) {
+ fnIsWow64Process(GetCurrentProcess(), &wow64);
+ }
+ debug("WOW64:\t\t%s\n", wow64 ? "yes" : "no");
+}
+
+void setConsoleFlag() {
+ console = TRUE;
+}
+
+void msgBox(const char* text) {
+ if (console) {
+ printf("%s: %s\n", errTitle, text);
+ } else {
+ MessageBox(NULL, text, errTitle, MB_OK);
+ }
+}
+
+void signalError() {
+ DWORD err = GetLastError();
+ if (err) {
+ LPVOID lpMsgBuf;
+ FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
+ | FORMAT_MESSAGE_FROM_SYSTEM
+ | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ err,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+ (LPTSTR) &lpMsgBuf,
+ 0,
+ NULL);
+ debug("Error:\t\t%s\n", (LPCTSTR) lpMsgBuf);
+ strcat(errMsg, "\n\n");
+ strcat(errMsg, (LPCTSTR) lpMsgBuf);
+ msgBox(errMsg);
+ LocalFree(lpMsgBuf);
+ } else {
+ msgBox(errMsg);
+ }
+ if (*errUrl) {
+ debug("Open URL:\t%s\n", errUrl);
+ ShellExecute(NULL, "open", errUrl, NULL, NULL, SW_SHOWNORMAL);
+ }
+ closeLogFile();
+}
+
+BOOL loadString(const int resID, char* buffer) {
+ HRSRC hResource;
+ HGLOBAL hResourceLoaded;
+ LPBYTE lpBuffer;
+
+ hResource = FindResourceEx(hModule, RT_RCDATA, MAKEINTRESOURCE(resID),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT));
+ if (NULL != hResource) {
+ hResourceLoaded = LoadResource(hModule, hResource);
+ if (NULL != hResourceLoaded) {
+ lpBuffer = (LPBYTE) LockResource(hResourceLoaded);
+ if (NULL != lpBuffer) {
+ int x = 0;
+ do {
+ buffer[x] = (char) lpBuffer[x];
+ } while (buffer[x++] != 0);
+ // debug("Resource %d:\t%s\n", resID, buffer);
+ return TRUE;
+ }
+ }
+ } else {
+ SetLastError(0);
+ }
+ return FALSE;
+}
+
+BOOL loadBool(const int resID) {
+ char boolStr[20] = {0};
+ loadString(resID, boolStr);
+ return strcmp(boolStr, TRUE_STR) == 0;
+}
+
+int loadInt(const int resID) {
+ char intStr[20] = {0};
+ loadString(resID, intStr);
+ return atoi(intStr);
+}
+
+BOOL regQueryValue(const char* regPath, unsigned char* buffer,
+ unsigned long bufferLength) {
+ HKEY hRootKey;
+ char* key;
+ char* value;
+ if (strstr(regPath, HKEY_CLASSES_ROOT_STR) == regPath) {
+ hRootKey = HKEY_CLASSES_ROOT;
+ } else if (strstr(regPath, HKEY_CURRENT_USER_STR) == regPath) {
+ hRootKey = HKEY_CURRENT_USER;
+ } else if (strstr(regPath, HKEY_LOCAL_MACHINE_STR) == regPath) {
+ hRootKey = HKEY_LOCAL_MACHINE;
+ } else if (strstr(regPath, HKEY_USERS_STR) == regPath) {
+ hRootKey = HKEY_USERS;
+ } else if (strstr(regPath, HKEY_CURRENT_CONFIG_STR) == regPath) {
+ hRootKey = HKEY_CURRENT_CONFIG;
+ } else {
+ return FALSE;
+ }
+ key = strchr(regPath, '\\') + 1;
+ value = strrchr(regPath, '\\') + 1;
+ *(value - 1) = 0;
+
+ HKEY hKey;
+ unsigned long datatype;
+ BOOL result = FALSE;
+ if ((wow64 && RegOpenKeyEx(hRootKey,
+ key,
+ 0,
+ KEY_READ | KEY_WOW64_64KEY,
+ &hKey) == ERROR_SUCCESS)
+ || RegOpenKeyEx(hRootKey,
+ key,
+ 0,
+ KEY_READ,
+ &hKey) == ERROR_SUCCESS) {
+ result = RegQueryValueEx(hKey, value, NULL, &datatype, buffer, &bufferLength)
+ == ERROR_SUCCESS;
+ RegCloseKey(hKey);
+ }
+ *(value - 1) = '\\';
+ return result;
+}
+
+void regSearch(const HKEY hKey, const char* keyName, const int searchType) {
+ DWORD x = 0;
+ unsigned long size = BIG_STR;
+ FILETIME time;
+ char buffer[BIG_STR] = {0};
+ while (RegEnumKeyEx(
+ hKey, // handle to key to enumerate
+ x++, // index of subkey to enumerate
+ buffer, // address of buffer for subkey name
+ &size, // address for size of subkey buffer
+ NULL, // reserved
+ NULL, // address of buffer for class string
+ NULL, // address for size of class buffer
+ &time) == ERROR_SUCCESS) {
+
+ if (strcmp(buffer, javaMinVer) >= 0
+ && (!*javaMaxVer || strcmp(buffer, javaMaxVer) <= 0)
+ && strcmp(buffer, foundJavaVer) > 0) {
+ strcpy(foundJavaVer, buffer);
+ strcpy(foundJavaKey, keyName);
+ appendPath(foundJavaKey, buffer);
+ foundJava = searchType;
+ debug("Match:\t\t%s\\%s\n", keyName, buffer);
+ } else {
+ debug("Ignore:\t\t%s\\%s\n", keyName, buffer);
+ }
+ size = BIG_STR;
+ }
+}
+
+void regSearchWow(const char* keyName, const int searchType) {
+ HKEY hKey;
+ debug("64-bit search:\t%s...\n", keyName);
+ if (wow64 && RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ keyName,
+ 0,
+ KEY_READ | KEY_WOW64_64KEY,
+ &hKey) == ERROR_SUCCESS) {
+
+ regSearch(hKey, keyName, searchType | KEY_WOW64_64KEY);
+ RegCloseKey(hKey);
+ if ((foundJava & KEY_WOW64_64KEY) != NO_JAVA_FOUND)
+ {
+ debug("Using 64-bit runtime.\n");
+ return;
+ }
+ }
+ debug("32-bit search:\t%s...\n", keyName);
+ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ keyName,
+ 0,
+ KEY_READ,
+ &hKey) == ERROR_SUCCESS) {
+ regSearch(hKey, keyName, searchType);
+ RegCloseKey(hKey);
+ }
+}
+
+void regSearchJreSdk(const char* jreKeyName, const char* sdkKeyName,
+ const int jdkPreference) {
+ if (jdkPreference == JDK_ONLY || jdkPreference == PREFER_JDK) {
+ regSearchWow(sdkKeyName, FOUND_SDK);
+ if (jdkPreference != JDK_ONLY) {
+ regSearchWow(jreKeyName, FOUND_JRE);
+ }
+ } else { // jdkPreference == JRE_ONLY or PREFER_JRE
+ regSearchWow(jreKeyName, FOUND_JRE);
+ if (jdkPreference != JRE_ONLY) {
+ regSearchWow(sdkKeyName, FOUND_SDK);
+ }
+ }
+}
+
+BOOL findJavaHome(char* path, const int jdkPreference) {
+ regSearchJreSdk("SOFTWARE\\JavaSoft\\Java Runtime Environment",
+ "SOFTWARE\\JavaSoft\\Java Development Kit",
+ jdkPreference);
+ if (foundJava == NO_JAVA_FOUND) {
+ regSearchJreSdk("SOFTWARE\\IBM\\Java2 Runtime Environment",
+ "SOFTWARE\\IBM\\Java Development Kit",
+ jdkPreference);
+ }
+ if (foundJava != NO_JAVA_FOUND) {
+ HKEY hKey;
+ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ foundJavaKey,
+ 0,
+ KEY_READ | (foundJava & KEY_WOW64_64KEY),
+ &hKey) == ERROR_SUCCESS) {
+ unsigned char buffer[BIG_STR] = {0};
+ unsigned long bufferlength = BIG_STR;
+ unsigned long datatype;
+ if (RegQueryValueEx(hKey, "JavaHome", NULL, &datatype, buffer,
+ &bufferlength) == ERROR_SUCCESS) {
+ int i = 0;
+ do {
+ path[i] = buffer[i];
+ } while (path[i++] != 0);
+ // (foundJava & FOUND_SDK) { // removed by fry
+ // appendPath(path, "jre");
+ //
+ RegCloseKey(hKey);
+ return TRUE;
+ }
+ RegCloseKey(hKey);
+ }
+ }
+ return FALSE;
+}
+
+/*
+ * Extract the executable name, returns path length.
+ */
+int getExePath(char* exePath) {
+ if (GetModuleFileName(hModule, exePath, _MAX_PATH) == 0) {
+ return -1;
+ }
+ return strrchr(exePath, '\\') - exePath;
+}
+
+void appendPath(char* basepath, const char* path) {
+ if (basepath[strlen(basepath) - 1] != '\\') {
+ strcat(basepath, "\\");
+ }
+ strcat(basepath, path);
+}
+
+void appendJavaw(char* jrePath) {
+ if (console) {
+ appendPath(jrePath, "bin\\java.exe");
+ } else {
+ appendPath(jrePath, "bin\\javaw.exe");
+ }
+}
+
+void appendLauncher(const BOOL setProcName, char* exePath,
+ const int pathLen, char* cmd) {
+ if (setProcName) {
+ char tmpspec[_MAX_PATH];
+ char tmpfile[_MAX_PATH];
+ strcpy(tmpspec, cmd);
+ strcat(tmpspec, LAUNCH4J_TMP_DIR);
+ tmpspec[strlen(tmpspec) - 1] = 0;
+ if (_stat(tmpspec, &statBuf) == 0) {
+ // Remove temp launchers and manifests
+ struct _finddata_t c_file;
+ long hFile;
+ appendPath(tmpspec, "*.exe");
+ strcpy(tmpfile, cmd);
+ strcat(tmpfile, LAUNCH4J_TMP_DIR);
+ char* filename = tmpfile + strlen(tmpfile);
+ if ((hFile = _findfirst(tmpspec, &c_file)) != -1L) {
+ do {
+ strcpy(filename, c_file.name);
+ debug("Unlink:\t\t%s\n", tmpfile);
+ _unlink(tmpfile);
+ strcat(tmpfile, MANIFEST);
+ debug("Unlink:\t\t%s\n", tmpfile);
+ _unlink(tmpfile);
+ } while (_findnext(hFile, &c_file) == 0);
+ }
+ _findclose(hFile);
+ } else {
+ if (_mkdir(tmpspec) != 0) {
+ debug("Mkdir failed:\t%s\n", tmpspec);
+ appendJavaw(cmd);
+ return;
+ }
+ }
+ char javaw[_MAX_PATH];
+ strcpy(javaw, cmd);
+ appendJavaw(javaw);
+ strcpy(tmpfile, cmd);
+ strcat(tmpfile, LAUNCH4J_TMP_DIR);
+ char* tmpfilename = tmpfile + strlen(tmpfile);
+ char* exeFilePart = exePath + pathLen + 1;
+
+ // Copy manifest
+ char manifest[_MAX_PATH] = {0};
+ strcpy(manifest, exePath);
+ strcat(manifest, MANIFEST);
+ if (_stat(manifest, &statBuf) == 0) {
+ strcat(tmpfile, exeFilePart);
+ strcat(tmpfile, MANIFEST);
+ debug("Copy:\t\t%s -> %s\n", manifest, tmpfile);
+ CopyFile(manifest, tmpfile, FALSE);
+ }
+
+ // Copy launcher
+ strcpy(tmpfilename, exeFilePart);
+ debug("Copy:\t\t%s -> %s\n", javaw, tmpfile);
+ if (CopyFile(javaw, tmpfile, FALSE)) {
+ strcpy(cmd, tmpfile);
+ return;
+ } else if (_stat(javaw, &statBuf) == 0) {
+ long fs = statBuf.st_size;
+ if (_stat(tmpfile, &statBuf) == 0 && fs == statBuf.st_size) {
+ debug("Reusing:\t\t%s\n", tmpfile);
+ strcpy(cmd, tmpfile);
+ return;
+ }
+ }
+ }
+ appendJavaw(cmd);
+}
+
+void appendAppClasspath(char* dst, const char* src, const char* classpath) {
+ strcat(dst, src);
+ if (*classpath) {
+ strcat(dst, ";");
+ }
+}
+
+BOOL isJrePathOk(const char* path) {
+ char javaw[_MAX_PATH];
+ BOOL result = FALSE;
+ if (*path) {
+ strcpy(javaw, path);
+ appendJavaw(javaw);
+ result = _stat(javaw, &statBuf) == 0;
+ }
+ debug("Check launcher:\t%s %s\n", javaw, result ? "(OK)" : "(n/a)");
+ return result;
+}
+
+/*
+ * Expand environment %variables%
+ */
+BOOL expandVars(char *dst, const char *src, const char *exePath, const int pathLen) {
+ char varName[STR];
+ char varValue[MAX_VAR_SIZE];
+ while (strlen(src) > 0) {
+ char *start = strchr(src, '%');
+ if (start != NULL) {
+ char *end = strchr(start + 1, '%');
+ if (end == NULL) {
+ return FALSE;
+ }
+ // Copy content up to %VAR%
+ strncat(dst, src, start - src);
+ // Insert value of %VAR%
+ *varName = 0;
+ strncat(varName, start + 1, end - start - 1);
+ // Remember value start for logging
+ char *varValue = dst + strlen(dst);
+ if (strcmp(varName, "EXEDIR") == 0) {
+ strncat(dst, exePath, pathLen);
+ } else if (strcmp(varName, "EXEFILE") == 0) {
+ strcat(dst, exePath);
+ } else if (strcmp(varName, "PWD") == 0) {
+ GetCurrentDirectory(_MAX_PATH, dst + strlen(dst));
+ } else if (strcmp(varName, "OLDPWD") == 0) {
+ strcat(dst, oldPwd);
+ } else if (strstr(varName, HKEY_STR) == varName) {
+ regQueryValue(varName, dst + strlen(dst), BIG_STR);
+ } else if (GetEnvironmentVariable(varName, varValue, MAX_VAR_SIZE) > 0) {
+ strcat(dst, varValue);
+ }
+ debug("Substitute:\t%s = %s\n", varName, varValue);
+ src = end + 1;
+ } else {
+ // Copy remaining content
+ strcat(dst, src);
+ break;
+ }
+ }
+ return TRUE;
+}
+
+void appendHeapSizes(char *dst) {
+ MEMORYSTATUS m;
+ memset(&m, 0, sizeof(m));
+ GlobalMemoryStatus(&m);
+
+ appendHeapSize(dst, INITIAL_HEAP_SIZE, INITIAL_HEAP_PERCENT,
+ m.dwAvailPhys, "-Xms");
+ appendHeapSize(dst, MAX_HEAP_SIZE, MAX_HEAP_PERCENT,
+ m.dwAvailPhys, "-Xmx");
+}
+
+void appendHeapSize(char *dst, const int absID, const int percentID,
+ const DWORD freeMemory, const char *option) {
+
+ const int mb = 1048576; // 1 MB
+ int abs = loadInt(absID);
+ int percent = loadInt(percentID);
+ int free = (long long) freeMemory * percent / (100 * mb); // 100% * 1 MB
+ int size = free > abs ? free : abs;
+ if (size > 0) {
+ debug("Heap %s:\t%d MB / %d%%, Free: %d MB, Heap size: %d MB\n",
+ option, abs, percent, freeMemory / mb, size);
+ strcat(dst, option);
+ _itoa(size, dst + strlen(dst), 10); // 10 -- radix
+ strcat(dst, "m ");
+ }
+}
+
+int prepare(const char *lpCmdLine) {
+ char tmp[MAX_ARGS] = {0};
+ hModule = GetModuleHandle(NULL);
+ if (hModule == NULL) {
+ return FALSE;
+ }
+
+ // Get executable path
+ char exePath[_MAX_PATH] = {0};
+ int pathLen = getExePath(exePath);
+ if (pathLen == -1) {
+ return FALSE;
+ }
+
+ // Initialize logging
+ if (strstr(lpCmdLine, "--l4j-debug") != NULL) {
+ hLog = openLogFile(exePath, pathLen);
+ if (hLog == NULL) {
+ return FALSE;
+ }
+ debug("\n\nCmdLine:\t%s %s\n", exePath, lpCmdLine);
+ }
+
+ setWow64Flag();
+
+ // Set default error message, title and optional support web site url.
+ loadString(SUPPORT_URL, errUrl);
+ loadString(ERR_TITLE, errTitle);
+ if (!loadString(STARTUP_ERR, errMsg)) {
+ return FALSE;
+ }
+
+ // Single instance
+ loadString(MUTEX_NAME, mutexName);
+ if (*mutexName) {
+ SECURITY_ATTRIBUTES security;
+ security.nLength = sizeof(SECURITY_ATTRIBUTES);
+ security.bInheritHandle = TRUE;
+ security.lpSecurityDescriptor = NULL;
+ CreateMutexA(&security, FALSE, mutexName);
+ if (GetLastError() == ERROR_ALREADY_EXISTS) {
+ debug("Instance already exists.");
+ return ERROR_ALREADY_EXISTS;
+ }
+ }
+
+ // Working dir
+ char tmp_path[_MAX_PATH] = {0};
+ GetCurrentDirectory(_MAX_PATH, oldPwd);
+ if (loadString(CHDIR, tmp_path)) {
+ strncpy(workingDir, exePath, pathLen);
+ appendPath(workingDir, tmp_path);
+ _chdir(workingDir);
+ debug("Working dir:\t%s\n", workingDir);
+ }
+
+ // Use bundled jre or find java
+ if (loadString(JRE_PATH, tmp_path)) {
+ char jrePath[MAX_ARGS] = {0};
+ expandVars(jrePath, tmp_path, exePath, pathLen);
+ debug("Bundled JRE:\t%s\n", jrePath);
+ if (jrePath[0] == '\\' || jrePath[1] == ':') {
+ // Absolute
+ strcpy(cmd, jrePath);
+ } else {
+ // Relative
+ strncpy(cmd, exePath, pathLen);
+ appendPath(cmd, jrePath);
+ }
+ }
+ if (!isJrePathOk(cmd)) {
+ if (!loadString(JAVA_MIN_VER, javaMinVer)) {
+ loadString(BUNDLED_JRE_ERR, errMsg);
+ return FALSE;
+ }
+ loadString(JAVA_MAX_VER, javaMaxVer);
+ if (!findJavaHome(cmd, loadInt(JDK_PREFERENCE))) {
+ loadString(JRE_VERSION_ERR, errMsg);
+ strcat(errMsg, " ");
+ strcat(errMsg, javaMinVer);
+ if (*javaMaxVer) {
+ strcat(errMsg, " - ");
+ strcat(errMsg, javaMaxVer);
+ }
+ loadString(DOWNLOAD_URL, errUrl);
+ return FALSE;
+ }
+ if (!isJrePathOk(cmd)) {
+ loadString(LAUNCHER_ERR, errMsg);
+ return FALSE;
+ }
+ }
+
+ // Append a path to the Path environment variable
+ char jreBinPath[_MAX_PATH];
+ strcpy(jreBinPath, cmd);
+ strcat(jreBinPath, "\\bin");
+ if (!appendToPathVar(jreBinPath)) {
+ return FALSE;
+ }
+
+ // Set environment variables
+ char envVars[MAX_VAR_SIZE] = {0};
+ loadString(ENV_VARIABLES, envVars);
+ char *var = strtok(envVars, "\t");
+ while (var != NULL) {
+ char *varValue = strchr(var, '=');
+ *varValue++ = 0;
+ *tmp = 0;
+ expandVars(tmp, varValue, exePath, pathLen);
+ debug("Set var:\t%s = %s\n", var, tmp);
+ SetEnvironmentVariable(var, tmp);
+ var = strtok(NULL, "\t");
+ }
+ *tmp = 0;
+
+ // Process priority
+ priority = loadInt(PRIORITY_CLASS);
+
+ // Custom process name
+ const BOOL setProcName = loadBool(SET_PROC_NAME)
+ && strstr(lpCmdLine, "--l4j-default-proc") == NULL;
+ const BOOL wrapper = loadBool(WRAPPER);
+
+ char jdk_path[_MAX_PATH] = {0}; // fry
+ strcpy(jdk_path, cmd);
+ //msgBox(jdk_path);
+
+ appendLauncher(setProcName, exePath, pathLen, cmd);
+
+ // Heap sizes
+ appendHeapSizes(args);
+
+ // JVM options
+ if (loadString(JVM_OPTIONS, tmp)) {
+ strcat(tmp, " ");
+ } else {
+ *tmp = 0;
+ }
+ /*
+ * Load additional JVM options from .l4j.ini file
+ * Options are separated by spaces or CRLF
+ * # starts an inline comment
+ */
+ strncpy(tmp_path, exePath, strlen(exePath) - 3);
+ strcat(tmp_path, "l4j.ini");
+ long hFile;
+ if ((hFile = _open(tmp_path, _O_RDONLY)) != -1) {
+ const int jvmOptLen = strlen(tmp);
+ char* src = tmp + jvmOptLen;
+ char* dst = src;
+ const int len = _read(hFile, src, MAX_ARGS - jvmOptLen - BIG_STR);
+ BOOL copy = TRUE;
+ int i;
+ for (i = 0; i < len; i++, src++) {
+ if (*src == '#') {
+ copy = FALSE;
+ } else if (*src == 13 || *src == 10) {
+ copy = TRUE;
+ if (dst > tmp && *(dst - 1) != ' ') {
+ *dst++ = ' ';
+ }
+ } else if (copy) {
+ *dst++ = *src;
+ }
+ }
+ *dst = 0;
+ if (len > 0 && *(dst - 1) != ' ') {
+ strcat(tmp, " ");
+ }
+ _close(hFile);
+ }
+
+ // Expand environment %variables%
+ expandVars(args, tmp, exePath, pathLen);
+
+ // MainClass + Classpath or Jar
+ char mainClass[STR] = {0};
+ char jar[_MAX_PATH] = {0};
+ loadString(JAR, jar);
+ if (loadString(MAIN_CLASS, mainClass)) {
+ if (!loadString(CLASSPATH, tmp)) {
+ return FALSE;
+ }
+ char exp[MAX_ARGS] = {0};
+ expandVars(exp, tmp, exePath, pathLen);
+ strcat(args, "-classpath \"");
+ if (wrapper) {
+ appendAppClasspath(args, exePath, exp);
+ } else if (*jar) {
+ appendAppClasspath(args, jar, exp);
+ }
+
+ // add tools.jar for JDK [fry]
+ char tools[_MAX_PATH] = { 0 };
+ sprintf(tools, "%s\\lib\\tools.jar", jdk_path);
+ appendAppClasspath(args, tools, exp);
+
+ // Deal with wildcards or >> strcat(args, exp); <<
+ char* cp = strtok(exp, ";");
+ while(cp != NULL) {
+ debug("Add classpath:\t%s\n", cp);
+ if (strpbrk(cp, "*?") != NULL) {
+ int len = strrchr(cp, '\\') - cp + 1;
+ strncpy(tmp_path, cp, len);
+ char* filename = tmp_path + len;
+ *filename = 0;
+ struct _finddata_t c_file;
+ long hFile;
+ if ((hFile = _findfirst(cp, &c_file)) != -1L) {
+ do {
+ strcpy(filename, c_file.name);
+ strcat(args, tmp_path);
+ strcat(args, ";");
+ debug(" \" :\t%s\n", tmp_path);
+ } while (_findnext(hFile, &c_file) == 0);
+ }
+ _findclose(hFile);
+ } else {
+ strcat(args, cp);
+ strcat(args, ";");
+ }
+ cp = strtok(NULL, ";");
+ }
+ *(args + strlen(args) - 1) = 0;
+
+ strcat(args, "\" ");
+ strcat(args, mainClass);
+ } else if (wrapper) {
+ strcat(args, "-jar \"");
+ strcat(args, exePath);
+ strcat(args, "\"");
+ } else {
+ strcat(args, "-jar \"");
+ strncat(args, exePath, pathLen);
+ appendPath(args, jar);
+ strcat(args, "\"");
+ }
+
+ // Constant command line args
+ if (loadString(CMD_LINE, tmp)) {
+ strcat(args, " ");
+ strcat(args, tmp);
+ }
+
+ // Command line args
+ if (*lpCmdLine) {
+ strcpy(tmp, lpCmdLine);
+ char* dst;
+ while ((dst = strstr(tmp, "--l4j-")) != NULL) {
+ char* src = strchr(dst, ' ');
+ if (src == NULL || *(src + 1) == 0) {
+ *dst = 0;
+ } else {
+ strcpy(dst, src + 1);
+ }
+ }
+ if (*tmp) {
+ strcat(args, " ");
+ strcat(args, tmp);
+ }
+ }
+
+ debug("Launcher:\t%s\n", cmd);
+ debug("Launcher args:\t%s\n", args);
+ debug("Args length:\t%d/32768 chars\n", strlen(args));
+ return TRUE;
+}
+
+void closeHandles() {
+ CloseHandle(pi.hThread);
+ CloseHandle(pi.hProcess);
+ closeLogFile();
+}
+
+/*
+ * Append a path to the Path environment variable
+ */
+BOOL appendToPathVar(const char* path) {
+ char chBuf[MAX_VAR_SIZE] = {0};
+
+ const int pathSize = GetEnvironmentVariable("Path", chBuf, MAX_VAR_SIZE);
+ if (MAX_VAR_SIZE - pathSize - 1 < strlen(path)) {
+ return FALSE;
+ }
+ strcat(chBuf, ";");
+ strcat(chBuf, path);
+ return SetEnvironmentVariable("Path", chBuf);
+}
+
+// may need to ignore STILL_ACTIVE (error code 259) here
+// http://msdn.microsoft.com/en-us/library/ms683189(VS.85).aspx
+DWORD execute(const BOOL wait) {
+ STARTUPINFO si;
+ memset(&pi, 0, sizeof(pi));
+ memset(&si, 0, sizeof(si));
+ si.cb = sizeof(si);
+
+ DWORD dwExitCode = -1;
+ char cmdline[MAX_ARGS];
+ strcpy(cmdline, "\"");
+ strcat(cmdline, cmd);
+ strcat(cmdline, "\" ");
+ strcat(cmdline, args);
+ if (CreateProcess(NULL, cmdline, NULL, NULL,
+ TRUE, priority, NULL, NULL, &si, &pi)) {
+ if (wait) {
+ WaitForSingleObject(pi.hProcess, INFINITE);
+ GetExitCodeProcess(pi.hProcess, &dwExitCode);
+ debug("Exit code:\t%d\n", dwExitCode);
+ closeHandles();
+ } else {
+ dwExitCode = 0;
+ }
+ }
+ return dwExitCode;
+}
diff --git a/build/windows/launcher/launch4j/head_src/head.h b/build/windows/launcher/launch4j/head_src/head.h
new file mode 100755
index 000000000..2e3bdb1d0
--- /dev/null
+++ b/build/windows/launcher/launch4j/head_src/head.h
@@ -0,0 +1,113 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2008 Grzegorz Kowal,
+ Ian Roberts (jdk preference patch)
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ Except as contained in this notice, the name(s) of the above copyright holders
+ shall not be used in advertising or otherwise to promote the sale, use or other
+ dealings in this Software without prior written authorization.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#ifndef _LAUNCH4J_HEAD__INCLUDED_
+#define _LAUNCH4J_HEAD__INCLUDED_
+
+#define WIN32_LEAN_AND_MEAN // VC - Exclude rarely-used stuff from Windows headers
+
+// Windows Header Files:
+#include
+
+// C RunTime Header Files
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define NO_JAVA_FOUND 0
+#define FOUND_JRE 1
+#define FOUND_SDK 2
+
+#define JRE_ONLY 0
+#define PREFER_JRE 1
+#define PREFER_JDK 2
+#define JDK_ONLY 3
+
+#define LAUNCH4J_TMP_DIR "\\launch4j-tmp\\"
+#define MANIFEST ".manifest"
+
+#define KEY_WOW64_64KEY 0x0100
+
+#define HKEY_STR "HKEY"
+#define HKEY_CLASSES_ROOT_STR "HKEY_CLASSES_ROOT"
+#define HKEY_CURRENT_USER_STR "HKEY_CURRENT_USER"
+#define HKEY_LOCAL_MACHINE_STR "HKEY_LOCAL_MACHINE"
+#define HKEY_USERS_STR "HKEY_USERS"
+#define HKEY_CURRENT_CONFIG_STR "HKEY_CURRENT_CONFIG"
+
+#define STR 128
+#define BIG_STR 1024
+#define MAX_VAR_SIZE 32767
+#define MAX_ARGS 32768
+
+#define TRUE_STR "true"
+#define FALSE_STR "false"
+
+#define debug(args...) if (hLog != NULL) fprintf(hLog, ## args);
+
+typedef void (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
+
+FILE* openLogFile(const char* exePath, const int pathLen);
+void closeLogFile();
+void msgBox(const char* text);
+void signalError();
+BOOL loadString(const int resID, char* buffer);
+BOOL loadBool(const int resID);
+int loadInt(const int resID);
+BOOL regQueryValue(const char* regPath, unsigned char* buffer,
+ unsigned long bufferLength);
+void regSearch(const HKEY hKey, const char* keyName, const int searchType);
+void regSearchWow(const char* keyName, const int searchType);
+void regSearchJreSdk(const char* jreKeyName, const char* sdkKeyName,
+ const int jdkPreference);
+BOOL findJavaHome(char* path, const int jdkPreference);
+int getExePath(char* exePath);
+void appendPath(char* basepath, const char* path);
+void appendJavaw(char* jrePath);
+void appendAppClasspath(char* dst, const char* src, const char* classpath);
+BOOL isJrePathOk(const char* path);
+BOOL expandVars(char *dst, const char *src, const char *exePath, const int pathLen);
+void appendHeapSizes(char *dst);
+void appendHeapSize(char *dst, const int absID, const int percentID,
+ const DWORD freeMemory, const char *option);
+int prepare(const char *lpCmdLine);
+void closeHandles();
+BOOL appendToPathVar(const char* path);
+DWORD execute(const BOOL wait);
+
+#endif // _LAUNCH4J_HEAD__INCLUDED_
diff --git a/build/windows/launcher/launch4j/head_src/resource.h b/build/windows/launcher/launch4j/head_src/resource.h
new file mode 100755
index 000000000..3c0f73cfc
--- /dev/null
+++ b/build/windows/launcher/launch4j/head_src/resource.h
@@ -0,0 +1,71 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2008 Grzegorz Kowal
+ Ian Roberts (jdk preference patch)
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ Except as contained in this notice, the name(s) of the above copyright holders
+ shall not be used in advertising or otherwise to promote the sale, use or other
+ dealings in this Software without prior written authorization.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+// ICON
+#define APP_ICON 1
+
+// BITMAP
+#define SPLASH_BITMAP 1
+
+// RCDATA
+#define JRE_PATH 1
+#define JAVA_MIN_VER 2
+#define JAVA_MAX_VER 3
+#define SHOW_SPLASH 4
+#define SPLASH_WAITS_FOR_WINDOW 5
+#define SPLASH_TIMEOUT 6
+#define SPLASH_TIMEOUT_ERR 7
+#define CHDIR 8
+#define SET_PROC_NAME 9
+#define ERR_TITLE 10
+#define GUI_HEADER_STAYS_ALIVE 11
+#define JVM_OPTIONS 12
+#define CMD_LINE 13
+#define JAR 14
+#define MAIN_CLASS 15
+#define CLASSPATH 16
+#define WRAPPER 17
+#define JDK_PREFERENCE 18
+#define ENV_VARIABLES 19
+#define PRIORITY_CLASS 20
+#define DOWNLOAD_URL 21
+#define SUPPORT_URL 22
+#define MUTEX_NAME 23
+#define INSTANCE_WINDOW_TITLE 24
+#define INITIAL_HEAP_SIZE 25
+#define INITIAL_HEAP_PERCENT 26
+#define MAX_HEAP_SIZE 27
+#define MAX_HEAP_PERCENT 28
+
+#define STARTUP_ERR 101
+#define BUNDLED_JRE_ERR 102
+#define JRE_VERSION_ERR 103
+#define LAUNCHER_ERR 104
+#define INSTANCE_ALREADY_EXISTS_MSG 105
diff --git a/build/windows/launcher/launch4j/launch4j.exe b/build/windows/launcher/launch4j/launch4j.exe
new file mode 100755
index 000000000..0e2eb2ba5
Binary files /dev/null and b/build/windows/launcher/launch4j/launch4j.exe differ
diff --git a/build/windows/launcher/launch4j/launch4j.jar b/build/windows/launcher/launch4j/launch4j.jar
new file mode 100755
index 000000000..ec68ae48d
Binary files /dev/null and b/build/windows/launcher/launch4j/launch4j.jar differ
diff --git a/build/windows/launcher/launch4j/launch4j.jfpr b/build/windows/launcher/launch4j/launch4j.jfpr
new file mode 100755
index 000000000..a2e63ebc5
Binary files /dev/null and b/build/windows/launcher/launch4j/launch4j.jfpr differ
diff --git a/build/windows/launcher/launch4j/launch4jc.exe b/build/windows/launcher/launch4j/launch4jc.exe
new file mode 100755
index 000000000..565cc2f07
Binary files /dev/null and b/build/windows/launcher/launch4j/launch4jc.exe differ
diff --git a/build/windows/launcher/launch4j/lib/JGoodies.Forms.LICENSE.txt b/build/windows/launcher/launch4j/lib/JGoodies.Forms.LICENSE.txt
new file mode 100755
index 000000000..9ba2419e7
--- /dev/null
+++ b/build/windows/launcher/launch4j/lib/JGoodies.Forms.LICENSE.txt
@@ -0,0 +1,31 @@
+
+ The BSD License for the JGoodies Forms
+ ======================================
+
+Copyright (c) 2002-2004 JGoodies Karsten Lentzsch. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ o Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ o Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ o Neither the name of JGoodies Karsten Lentzsch nor the names of
+ its contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/build/windows/launcher/launch4j/lib/JGoodies.Looks.LICENSE.txt b/build/windows/launcher/launch4j/lib/JGoodies.Looks.LICENSE.txt
new file mode 100755
index 000000000..8bbefa2eb
--- /dev/null
+++ b/build/windows/launcher/launch4j/lib/JGoodies.Looks.LICENSE.txt
@@ -0,0 +1,31 @@
+
+ The BSD License for the JGoodies Looks
+ ======================================
+
+Copyright (c) 2001-2007 JGoodies Karsten Lentzsch. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ o Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ o Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ o Neither the name of JGoodies Karsten Lentzsch nor the names of
+ its contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/build/windows/launcher/launch4j/lib/Nuvola.Icon.Theme.LICENSE.txt b/build/windows/launcher/launch4j/lib/Nuvola.Icon.Theme.LICENSE.txt
new file mode 100755
index 000000000..cbee875ba
--- /dev/null
+++ b/build/windows/launcher/launch4j/lib/Nuvola.Icon.Theme.LICENSE.txt
@@ -0,0 +1,504 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ , 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/build/windows/launcher/launch4j/lib/XStream.LICENSE.txt b/build/windows/launcher/launch4j/lib/XStream.LICENSE.txt
new file mode 100755
index 000000000..5ccad8694
--- /dev/null
+++ b/build/windows/launcher/launch4j/lib/XStream.LICENSE.txt
@@ -0,0 +1,27 @@
+(BSD Style License)
+
+Copyright (c) 2003-2004, Joe Walnes
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list of
+conditions and the following disclaimer. Redistributions in binary form must reproduce
+the above copyright notice, this list of conditions and the following disclaimer in
+the documentation and/or other materials provided with the distribution.
+
+Neither the name of XStream nor the names of its contributors may be used to endorse
+or promote products derived from this software without specific prior written
+permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
+WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGE.
diff --git a/build/windows/launcher/launch4j/lib/commons-beanutils.jar b/build/windows/launcher/launch4j/lib/commons-beanutils.jar
new file mode 100755
index 000000000..b1b89c9c9
Binary files /dev/null and b/build/windows/launcher/launch4j/lib/commons-beanutils.jar differ
diff --git a/build/windows/launcher/launch4j/lib/commons-logging.jar b/build/windows/launcher/launch4j/lib/commons-logging.jar
new file mode 100755
index 000000000..b73a80fab
Binary files /dev/null and b/build/windows/launcher/launch4j/lib/commons-logging.jar differ
diff --git a/build/windows/launcher/launch4j/lib/commons.LICENSE.txt b/build/windows/launcher/launch4j/lib/commons.LICENSE.txt
new file mode 100755
index 000000000..fdb647522
--- /dev/null
+++ b/build/windows/launcher/launch4j/lib/commons.LICENSE.txt
@@ -0,0 +1,50 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) @year@ The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Apache Cocoon" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation and was originally created by
+ Stefano Mazzocchi . For more information on the Apache
+ Software Foundation, please see .
+
+*/
diff --git a/build/windows/launcher/launch4j/lib/forms.jar b/build/windows/launcher/launch4j/lib/forms.jar
new file mode 100755
index 000000000..aed060a49
Binary files /dev/null and b/build/windows/launcher/launch4j/lib/forms.jar differ
diff --git a/build/windows/launcher/launch4j/lib/formsrt.jar b/build/windows/launcher/launch4j/lib/formsrt.jar
new file mode 100755
index 000000000..e0de6ecf1
Binary files /dev/null and b/build/windows/launcher/launch4j/lib/formsrt.jar differ
diff --git a/build/windows/launcher/launch4j/lib/foxtrot.LICENSE.txt b/build/windows/launcher/launch4j/lib/foxtrot.LICENSE.txt
new file mode 100755
index 000000000..5fa4019d5
--- /dev/null
+++ b/build/windows/launcher/launch4j/lib/foxtrot.LICENSE.txt
@@ -0,0 +1,25 @@
+Copyright (c) 2002, Simone Bordet & Marco Cravero
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted
+provided that the following conditions are met:
+
+ - Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ - Neither the name of Foxtrot nor the names of the contributors may be used
+ to endorse or promote products derived from this software without specific prior
+ written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
+OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/build/windows/launcher/launch4j/lib/foxtrot.jar b/build/windows/launcher/launch4j/lib/foxtrot.jar
new file mode 100755
index 000000000..f39103a09
Binary files /dev/null and b/build/windows/launcher/launch4j/lib/foxtrot.jar differ
diff --git a/build/windows/launcher/launch4j/lib/looks.jar b/build/windows/launcher/launch4j/lib/looks.jar
new file mode 100755
index 000000000..d2c47c743
Binary files /dev/null and b/build/windows/launcher/launch4j/lib/looks.jar differ
diff --git a/build/windows/launcher/launch4j/lib/xstream.jar b/build/windows/launcher/launch4j/lib/xstream.jar
new file mode 100755
index 000000000..392e1c937
Binary files /dev/null and b/build/windows/launcher/launch4j/lib/xstream.jar differ
diff --git a/build/windows/launcher/launch4j/manifest/uac.exe.manifest b/build/windows/launcher/launch4j/manifest/uac.exe.manifest
new file mode 100755
index 000000000..3041fbc5b
--- /dev/null
+++ b/build/windows/launcher/launch4j/manifest/uac.exe.manifest
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build/windows/launcher/launch4j/manifest/xp-themes.exe.manifest b/build/windows/launcher/launch4j/manifest/xp-themes.exe.manifest
new file mode 100755
index 000000000..e2c7511f9
--- /dev/null
+++ b/build/windows/launcher/launch4j/manifest/xp-themes.exe.manifest
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build/windows/launcher/launch4j/src/images/asterix-o.gif b/build/windows/launcher/launch4j/src/images/asterix-o.gif
new file mode 100755
index 000000000..f5cf3b307
Binary files /dev/null and b/build/windows/launcher/launch4j/src/images/asterix-o.gif differ
diff --git a/build/windows/launcher/launch4j/src/images/asterix.gif b/build/windows/launcher/launch4j/src/images/asterix.gif
new file mode 100755
index 000000000..ba801670a
Binary files /dev/null and b/build/windows/launcher/launch4j/src/images/asterix.gif differ
diff --git a/build/windows/launcher/launch4j/src/images/build.png b/build/windows/launcher/launch4j/src/images/build.png
new file mode 100755
index 000000000..625285f0b
Binary files /dev/null and b/build/windows/launcher/launch4j/src/images/build.png differ
diff --git a/build/windows/launcher/launch4j/src/images/button_ok.png b/build/windows/launcher/launch4j/src/images/button_ok.png
new file mode 100755
index 000000000..5b0f6a617
Binary files /dev/null and b/build/windows/launcher/launch4j/src/images/button_ok.png differ
diff --git a/build/windows/launcher/launch4j/src/images/cancel16.png b/build/windows/launcher/launch4j/src/images/cancel16.png
new file mode 100755
index 000000000..a432b492c
Binary files /dev/null and b/build/windows/launcher/launch4j/src/images/cancel16.png differ
diff --git a/build/windows/launcher/launch4j/src/images/down16.png b/build/windows/launcher/launch4j/src/images/down16.png
new file mode 100755
index 000000000..f3bc4cd09
Binary files /dev/null and b/build/windows/launcher/launch4j/src/images/down16.png differ
diff --git a/build/windows/launcher/launch4j/src/images/edit_add16.png b/build/windows/launcher/launch4j/src/images/edit_add16.png
new file mode 100755
index 000000000..e9485082e
Binary files /dev/null and b/build/windows/launcher/launch4j/src/images/edit_add16.png differ
diff --git a/build/windows/launcher/launch4j/src/images/info.png b/build/windows/launcher/launch4j/src/images/info.png
new file mode 100755
index 000000000..eb37d9a08
Binary files /dev/null and b/build/windows/launcher/launch4j/src/images/info.png differ
diff --git a/build/windows/launcher/launch4j/src/images/new.png b/build/windows/launcher/launch4j/src/images/new.png
new file mode 100755
index 000000000..6e2700ad9
Binary files /dev/null and b/build/windows/launcher/launch4j/src/images/new.png differ
diff --git a/build/windows/launcher/launch4j/src/images/new16.png b/build/windows/launcher/launch4j/src/images/new16.png
new file mode 100755
index 000000000..f38d02ee5
Binary files /dev/null and b/build/windows/launcher/launch4j/src/images/new16.png differ
diff --git a/build/windows/launcher/launch4j/src/images/ok16.png b/build/windows/launcher/launch4j/src/images/ok16.png
new file mode 100755
index 000000000..5b0f6a617
Binary files /dev/null and b/build/windows/launcher/launch4j/src/images/ok16.png differ
diff --git a/build/windows/launcher/launch4j/src/images/open.png b/build/windows/launcher/launch4j/src/images/open.png
new file mode 100755
index 000000000..a801665fd
Binary files /dev/null and b/build/windows/launcher/launch4j/src/images/open.png differ
diff --git a/build/windows/launcher/launch4j/src/images/open16.png b/build/windows/launcher/launch4j/src/images/open16.png
new file mode 100755
index 000000000..5321c17c6
Binary files /dev/null and b/build/windows/launcher/launch4j/src/images/open16.png differ
diff --git a/build/windows/launcher/launch4j/src/images/run.png b/build/windows/launcher/launch4j/src/images/run.png
new file mode 100755
index 000000000..b41fa2b97
Binary files /dev/null and b/build/windows/launcher/launch4j/src/images/run.png differ
diff --git a/build/windows/launcher/launch4j/src/images/save.png b/build/windows/launcher/launch4j/src/images/save.png
new file mode 100755
index 000000000..74b37b0b5
Binary files /dev/null and b/build/windows/launcher/launch4j/src/images/save.png differ
diff --git a/build/windows/launcher/launch4j/src/images/up16.png b/build/windows/launcher/launch4j/src/images/up16.png
new file mode 100755
index 000000000..184c118b6
Binary files /dev/null and b/build/windows/launcher/launch4j/src/images/up16.png differ
diff --git a/build/windows/launcher/launch4j/src/launch4j.properties b/build/windows/launcher/launch4j/src/launch4j.properties
new file mode 100755
index 000000000..463c7a034
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/launch4j.properties
@@ -0,0 +1,2 @@
+versionNumber=3.0.1.0
+version=3.0.1
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/Builder.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/Builder.java
new file mode 100755
index 000000000..d7badc7f3
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/Builder.java
@@ -0,0 +1,207 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on 2005-04-24
+ */
+package net.sf.launch4j;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import net.sf.launch4j.binding.InvariantViolationException;
+import net.sf.launch4j.config.Config;
+import net.sf.launch4j.config.ConfigPersister;
+
+/**
+ * @author Copyright (C) 2005 Grzegorz Kowal
+ */
+public class Builder {
+ private final Log _log;
+ private final File _basedir;
+
+ public Builder(Log log) {
+ _log = log;
+ _basedir = Util.getJarBasedir();
+ }
+
+ public Builder(Log log, File basedir) {
+ _log = log;
+ _basedir = basedir;
+ }
+
+ /**
+ * @return Output file path.
+ */
+ public File build() throws BuilderException {
+ final Config c = ConfigPersister.getInstance().getConfig();
+ try {
+ c.validate();
+ } catch (InvariantViolationException e) {
+ throw new BuilderException(e.getMessage());
+ }
+ File rc = null;
+ File ro = null;
+ File outfile = null;
+ FileInputStream is = null;
+ FileOutputStream os = null;
+ final RcBuilder rcb = new RcBuilder();
+ try {
+ rc = rcb.build(c);
+ ro = Util.createTempFile("o");
+ outfile = ConfigPersister.getInstance().getOutputFile();
+
+ Cmd resCmd = new Cmd(_basedir);
+ resCmd.addExe("windres")
+ .add(Util.WINDOWS_OS ? "--preprocessor=type" : "--preprocessor=cat")
+ .add("-J rc -O coff -F pe-i386")
+ .addAbsFile(rc)
+ .addAbsFile(ro);
+ _log.append(Messages.getString("Builder.compiling.resources"));
+ resCmd.exec(_log);
+
+ Cmd ldCmd = new Cmd(_basedir);
+ ldCmd.addExe("ld")
+ .add("-mi386pe")
+ .add("--oformat pei-i386")
+ .add((c.getHeaderType().equals(Config.GUI_HEADER))
+ ? "--subsystem windows" : "--subsystem console")
+ .add("-s") // strip symbols
+ .addFiles(c.getHeaderObjects())
+ .addAbsFile(ro)
+ .addFiles(c.getLibs())
+ .add("-o")
+ .addAbsFile(outfile);
+ _log.append(Messages.getString("Builder.linking"));
+ ldCmd.exec(_log);
+
+ if (!c.isDontWrapJar()) {
+ _log.append(Messages.getString("Builder.wrapping"));
+ int len;
+ byte[] buffer = new byte[1024];
+ is = new FileInputStream(Util.getAbsoluteFile(
+ ConfigPersister.getInstance().getConfigPath(), c.getJar()));
+ os = new FileOutputStream(outfile, true);
+ while ((len = is.read(buffer)) > 0) {
+ os.write(buffer, 0, len);
+ }
+ }
+ _log.append(Messages.getString("Builder.success") + outfile.getPath());
+ return outfile;
+ } catch (IOException e) {
+ Util.delete(outfile);
+ _log.append(e.getMessage());
+ throw new BuilderException(e);
+ } catch (ExecException e) {
+ Util.delete(outfile);
+ String msg = e.getMessage();
+ if (msg != null && msg.indexOf("windres") != -1) {
+ if (e.getErrLine() != -1) {
+ _log.append(Messages.getString("Builder.line.has.errors",
+ String.valueOf(e.getErrLine())));
+ _log.append(rcb.getLine(e.getErrLine()));
+ } else {
+ _log.append(Messages.getString("Builder.generated.resource.file"));
+ _log.append(rcb.getContent());
+ }
+ }
+ throw new BuilderException(e);
+ } finally {
+ Util.close(is);
+ Util.close(os);
+ Util.delete(rc);
+ Util.delete(ro);
+ }
+ }
+}
+
+class Cmd {
+ private final List _cmd = new ArrayList();
+ private final File _basedir;
+ private final File _bindir;
+
+ public Cmd(File basedir) {
+ _basedir = basedir;
+ String path = System.getProperty("launch4j.bindir");
+ if (path == null) {
+ _bindir = new File(basedir, "bin");
+ } else {
+ File bindir = new File(path);
+ _bindir = bindir.isAbsolute() ? bindir : new File(basedir, path);
+ }
+ }
+
+ public Cmd add(String s) {
+ StringTokenizer st = new StringTokenizer(s);
+ while (st.hasMoreTokens()) {
+ _cmd.add(st.nextToken());
+ }
+ return this;
+ }
+
+ public Cmd addAbsFile(File file) {
+ _cmd.add(file.getPath());
+ return this;
+ }
+
+ public Cmd addFile(String pathname) {
+ _cmd.add(new File(_basedir, pathname).getPath());
+ return this;
+ }
+
+ public Cmd addExe(String pathname) {
+ if (Util.WINDOWS_OS) {
+ pathname += ".exe";
+ }
+ _cmd.add(new File(_bindir, pathname).getPath());
+ return this;
+ }
+
+ public Cmd addFiles(List files) {
+ for (Iterator iter = files.iterator(); iter.hasNext();) {
+ addFile((String) iter.next());
+ }
+ return this;
+ }
+
+ public void exec(Log log) throws ExecException {
+ String[] cmd = (String[]) _cmd.toArray(new String[_cmd.size()]);
+ Util.exec(cmd, log);
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/BuilderException.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/BuilderException.java
new file mode 100755
index 000000000..a84c2e279
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/BuilderException.java
@@ -0,0 +1,52 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on May 13, 2005
+ */
+package net.sf.launch4j;
+
+/**
+ * @author Copyright (C) 2005 Grzegorz Kowal
+ */
+public class BuilderException extends Exception {
+ public BuilderException() {}
+
+ public BuilderException(Throwable t) {
+ super(t);
+ }
+
+ public BuilderException(String msg) {
+ super(msg);
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/ExecException.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/ExecException.java
new file mode 100755
index 000000000..236ae780f
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/ExecException.java
@@ -0,0 +1,66 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on May 14, 2005
+ */
+package net.sf.launch4j;
+
+/**
+ * @author Copyright (C) 2005 Grzegorz Kowal
+ */
+public class ExecException extends Exception {
+ private final int _errLine;
+
+ public ExecException(Throwable t, int errLine) {
+ super(t);
+ _errLine = errLine;
+ }
+
+ public ExecException(Throwable t) {
+ this(t, -1);
+ }
+
+ public ExecException(String msg, int errLine) {
+ super(msg);
+ _errLine = errLine;
+ }
+
+ public ExecException(String msg) {
+ this(msg, -1);
+ }
+
+ public int getErrLine() {
+ return _errLine;
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/FileChooserFilter.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/FileChooserFilter.java
new file mode 100755
index 000000000..5199a6deb
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/FileChooserFilter.java
@@ -0,0 +1,76 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on 2004-01-15
+ */
+package net.sf.launch4j;
+
+import java.io.File;
+
+import javax.swing.filechooser.FileFilter;
+
+/**
+ * @author Copyright (C) 2004 Grzegorz Kowal
+ */
+public class FileChooserFilter extends FileFilter {
+ String _description;
+ String[] _extensions;
+
+ public FileChooserFilter(String description, String extension) {
+ _description = description;
+ _extensions = new String[] {extension};
+ }
+
+ public FileChooserFilter(String description, String[] extensions) {
+ _description = description;
+ _extensions = extensions;
+ }
+
+ public boolean accept(File f) {
+ if (f.isDirectory()) {
+ return true;
+ }
+ String ext = Util.getExtension(f);
+ for (int i = 0; i < _extensions.length; i++) {
+ if (ext.toLowerCase().equals(_extensions[i].toLowerCase())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public String getDescription() {
+ return _description;
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/Log.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/Log.java
new file mode 100755
index 000000000..c4d591b0c
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/Log.java
@@ -0,0 +1,105 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on May 12, 2005
+ */
+package net.sf.launch4j;
+
+import javax.swing.JTextArea;
+import javax.swing.SwingUtilities;
+
+/**
+ * @author Copyright (C) 2005 Grzegorz Kowal
+ */
+public abstract class Log {
+ private static final Log _consoleLog = new ConsoleLog();
+ private static final Log _antLog = new AntLog();
+
+ public abstract void clear();
+ public abstract void append(String line);
+
+ public static Log getConsoleLog() {
+ return _consoleLog;
+ }
+
+ public static Log getAntLog() {
+ return _antLog;
+ }
+
+ public static Log getSwingLog(JTextArea textArea) {
+ return new SwingLog(textArea);
+ }
+}
+
+class ConsoleLog extends Log {
+ public void clear() {
+ System.out.println("\n");
+ }
+
+ public void append(String line) {
+ System.out.println("launch4j: " + line);
+ }
+}
+
+class AntLog extends Log {
+ public void clear() {
+ System.out.println("\n");
+ }
+
+ public void append(String line) {
+ System.out.println(line);
+ }
+}
+
+class SwingLog extends Log {
+ private final JTextArea _textArea;
+
+ public SwingLog(JTextArea textArea) {
+ _textArea = textArea;
+ }
+
+ public void clear() {
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ _textArea.setText("");
+ }});
+ }
+
+ public void append(final String line) {
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ _textArea.append(line + "\n");
+ }});
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/Main.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/Main.java
new file mode 100755
index 000000000..45f84ad79
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/Main.java
@@ -0,0 +1,99 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2008 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on Apr 21, 2005
+ */
+package net.sf.launch4j;
+
+import java.io.File;
+import java.io.InputStream;
+import java.util.Properties;
+
+import net.sf.launch4j.config.ConfigPersister;
+import net.sf.launch4j.formimpl.MainFrame;
+
+/**
+ * @author Copyright (C) 2005 Grzegorz Kowal
+ */
+public class Main {
+ private static String _name;
+ private static String _description;
+
+ public static void main(String[] args) {
+ try {
+ Properties props = new Properties();
+ InputStream in = Main.class.getClassLoader()
+ .getResourceAsStream("launch4j.properties");
+ props.load(in);
+ in.close();
+ setDescription(props);
+
+ if (args.length == 0) {
+ ConfigPersister.getInstance().createBlank();
+ MainFrame.createInstance();
+ } else if (args.length == 1 && !args[0].startsWith("-")) {
+ ConfigPersister.getInstance().load(new File(args[0]));
+ Builder b = new Builder(Log.getConsoleLog());
+ b.build();
+ } else {
+ System.out.println(_description
+ + Messages.getString("Main.usage")
+ + ": launch4j config.xml");
+ }
+ } catch (Exception e) {
+ Log.getConsoleLog().append(e.getMessage());
+ }
+ }
+
+ public static String getName() {
+ return _name;
+ }
+
+ public static String getDescription() {
+ return _description;
+ }
+
+ private static void setDescription(Properties props) {
+ _name = "Launch4j " + props.getProperty("version");
+ _description = _name +
+ " (http://launch4j.sourceforge.net/)\n" +
+ "Cross-platform Java application wrapper" +
+ " for creating Windows native executables.\n\n" +
+ "Copyright (C) 2004, 2008 Grzegorz Kowal\n\n" +
+ "Launch4j comes with ABSOLUTELY NO WARRANTY.\n" +
+ "This is free software, licensed under the BSD License.\n" +
+ "This product includes software developed by the Apache Software Foundation" +
+ " (http://www.apache.org/).";
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/Messages.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/Messages.java
new file mode 100755
index 000000000..35d4c8950
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/Messages.java
@@ -0,0 +1,78 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package net.sf.launch4j;
+
+import java.text.MessageFormat;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+public class Messages {
+ private static final String BUNDLE_NAME = "net.sf.launch4j.messages";
+
+ private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle
+ .getBundle(BUNDLE_NAME);
+ private static final MessageFormat FORMATTER = new MessageFormat("");
+
+ private Messages() {
+ }
+
+ public static String getString(String key) {
+ try {
+ return RESOURCE_BUNDLE.getString(key);
+ } catch (MissingResourceException e) {
+ return '!' + key + '!';
+ }
+ }
+
+ public static String getString(String key, String arg0) {
+ return getString(key, new Object[] {arg0});
+ }
+
+ public static String getString(String key, String arg0, String arg1) {
+ return getString(key, new Object[] {arg0, arg1});
+ }
+
+ public static String getString(String key, String arg0, String arg1, String arg2) {
+ return getString(key, new Object[] {arg0, arg1, arg2});
+ }
+
+ public static String getString(String key, Object[] args) {
+ try {
+ FORMATTER.applyPattern(RESOURCE_BUNDLE.getString(key));
+ return FORMATTER.format(args);
+ } catch (MissingResourceException e) {
+ return '!' + key + '!';
+ }
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/OptionParser.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/OptionParser.java
new file mode 100755
index 000000000..bb2432c8e
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/OptionParser.java
@@ -0,0 +1,71 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on 2005-04-24
+ */
+package net.sf.launch4j;
+
+//import net.sf.launch4j.config.Config;
+
+//import org.apache.commons.cli.CommandLine;
+//import org.apache.commons.cli.CommandLineParser;
+//import org.apache.commons.cli.HelpFormatter;
+//import org.apache.commons.cli.Options;
+//import org.apache.commons.cli.ParseException;
+//import org.apache.commons.cli.PosixParser;
+
+/**
+ * @author Copyright (C) 2005 Grzegorz Kowal
+ */
+public class OptionParser {
+
+// private final Options _options;
+//
+// public OptionParser() {
+// _options = new Options();
+// _options.addOption("h", "header", true, "header");
+// }
+//
+// public Config parse(Config c, String[] args) throws ParseException {
+// CommandLineParser parser = new PosixParser();
+// CommandLine cl = parser.parse(_options, args);
+// c.setJar(getFile(props, Config.JAR));
+// c.setOutfile(getFile(props, Config.OUTFILE));
+// }
+//
+// public void printHelp() {
+// HelpFormatter formatter = new HelpFormatter();
+// formatter.printHelp("launch4j", _options);
+// }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/RcBuilder.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/RcBuilder.java
new file mode 100755
index 000000000..f8885e3e6
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/RcBuilder.java
@@ -0,0 +1,340 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on 2005-04-24
+ */
+package net.sf.launch4j;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.List;
+
+import net.sf.launch4j.config.Config;
+import net.sf.launch4j.config.ConfigPersister;
+import net.sf.launch4j.config.Jre;
+import net.sf.launch4j.config.Msg;
+import net.sf.launch4j.config.Splash;
+import net.sf.launch4j.config.VersionInfo;
+
+/**
+ * @author Copyright (C) 2005 Grzegorz Kowal
+ */
+public class RcBuilder {
+
+ // winnt.h
+ public static final int LANG_NEUTRAL = 0;
+ public static final int SUBLANG_NEUTRAL = 0;
+ public static final int SUBLANG_DEFAULT = 1;
+ public static final int SUBLANG_SYS_DEFAULT = 2;
+
+ // MANIFEST
+ public static final int MANIFEST = 1;
+
+ // ICON
+ public static final int APP_ICON = 1;
+
+ // BITMAP
+ public static final int SPLASH_BITMAP = 1;
+
+ // RCDATA
+ public static final int JRE_PATH = 1;
+ public static final int JAVA_MIN_VER = 2;
+ public static final int JAVA_MAX_VER = 3;
+ public static final int SHOW_SPLASH = 4;
+ public static final int SPLASH_WAITS_FOR_WINDOW = 5;
+ public static final int SPLASH_TIMEOUT = 6;
+ public static final int SPLASH_TIMEOUT_ERR = 7;
+ public static final int CHDIR = 8;
+ public static final int SET_PROC_NAME = 9;
+ public static final int ERR_TITLE = 10;
+ public static final int GUI_HEADER_STAYS_ALIVE = 11;
+ public static final int JVM_OPTIONS = 12;
+ public static final int CMD_LINE = 13;
+ public static final int JAR = 14;
+ public static final int MAIN_CLASS = 15;
+ public static final int CLASSPATH = 16;
+ public static final int WRAPPER = 17;
+ public static final int JDK_PREFERENCE = 18;
+ public static final int ENV_VARIABLES = 19;
+ public static final int PRIORITY_CLASS = 20;
+ public static final int DOWNLOAD_URL = 21;
+ public static final int SUPPORT_URL = 22;
+ public static final int MUTEX_NAME = 23;
+ public static final int INSTANCE_WINDOW_TITLE = 24;
+ public static final int INITIAL_HEAP_SIZE = 25;
+ public static final int INITIAL_HEAP_PERCENT = 26;
+ public static final int MAX_HEAP_SIZE = 27;
+ public static final int MAX_HEAP_PERCENT = 28;
+
+ public static final int STARTUP_ERR = 101;
+ public static final int BUNDLED_JRE_ERR = 102;
+ public static final int JRE_VERSION_ERR = 103;
+ public static final int LAUNCHER_ERR = 104;
+ public static final int INSTANCE_ALREADY_EXISTS_MSG = 105;
+
+ private final StringBuffer _sb = new StringBuffer();
+
+ public String getContent() {
+ return _sb.toString();
+ }
+
+ public String getLine(int line) {
+ return _sb.toString().split("\n")[line - 1];
+ }
+
+ public File build(Config c) throws IOException {
+ _sb.append("LANGUAGE ");
+ _sb.append(LANG_NEUTRAL);
+ _sb.append(", ");
+ _sb.append(SUBLANG_DEFAULT);
+ _sb.append('\n');
+ addVersionInfo(c.getVersionInfo());
+ addJre(c.getJre());
+ addManifest(MANIFEST, c.getManifest());
+ addIcon(APP_ICON, c.getIcon());
+ addText(ERR_TITLE, c.getErrTitle());
+ addText(DOWNLOAD_URL, c.getDownloadUrl());
+ addText(SUPPORT_URL, c.getSupportUrl());
+ addText(CMD_LINE, c.getCmdLine());
+ addWindowsPath(CHDIR, c.getChdir());
+ addText(PRIORITY_CLASS, String.valueOf(c.getPriorityClass()));
+ addTrue(SET_PROC_NAME, c.isCustomProcName());
+ addTrue(GUI_HEADER_STAYS_ALIVE, c.isStayAlive());
+ addSplash(c.getSplash());
+ addMessages(c);
+
+ if (c.getSingleInstance() != null) {
+ addText(MUTEX_NAME, c.getSingleInstance().getMutexName());
+ addText(INSTANCE_WINDOW_TITLE, c.getSingleInstance().getWindowTitle());
+ }
+
+ if (c.getVariables() != null && !c.getVariables().isEmpty()) {
+ StringBuffer vars = new StringBuffer();
+ append(vars, c.getVariables(), "\t");
+ addText(ENV_VARIABLES, vars.toString());
+ }
+
+ // MAIN_CLASS / JAR
+ addTrue(WRAPPER, !c.isDontWrapJar());
+ if (c.getClassPath() != null) {
+ addText(MAIN_CLASS, c.getClassPath().getMainClass());
+ addWindowsPath(CLASSPATH, c.getClassPath().getPathsString());
+ }
+ if (c.isDontWrapJar() && c.getJar() != null) {
+ addWindowsPath(JAR, c.getJar().getPath());
+ }
+
+ File f = Util.createTempFile("rc");
+ BufferedWriter w = new BufferedWriter(new FileWriter(f));
+ w.write(_sb.toString());
+ w.close();
+ return f;
+ }
+
+ private void addVersionInfo(VersionInfo v) {
+ if (v == null) {
+ return;
+ }
+ _sb.append("1 VERSIONINFO\n");
+ _sb.append("FILEVERSION ");
+ _sb.append(v.getFileVersion().replaceAll("\\.", ", "));
+ _sb.append("\nPRODUCTVERSION ");
+ _sb.append(v.getProductVersion().replaceAll("\\.", ", "));
+ _sb.append("\nFILEFLAGSMASK 0\n" +
+ "FILEOS 0x40000\n" +
+ "FILETYPE 1\n" +
+ "{\n" +
+ " BLOCK \"StringFileInfo\"\n" +
+ " {\n" +
+ " BLOCK \"040904E4\"\n" + // English
+ " {\n");
+ addVerBlockValue("CompanyName", v.getCompanyName());
+ addVerBlockValue("FileDescription", v.getFileDescription());
+ addVerBlockValue("FileVersion", v.getTxtFileVersion());
+ addVerBlockValue("InternalName", v.getInternalName());
+ addVerBlockValue("LegalCopyright", v.getCopyright());
+ addVerBlockValue("OriginalFilename", v.getOriginalFilename());
+ addVerBlockValue("ProductName", v.getProductName());
+ addVerBlockValue("ProductVersion", v.getTxtProductVersion());
+ _sb.append(" }\n }\nBLOCK \"VarFileInfo\"\n{\nVALUE \"Translation\", 0x0409, 0x04E4\n}\n}");
+ }
+
+ private void addJre(Jre jre) {
+ addWindowsPath(JRE_PATH, jre.getPath());
+ addText(JAVA_MIN_VER, jre.getMinVersion());
+ addText(JAVA_MAX_VER, jre.getMaxVersion());
+ addText(JDK_PREFERENCE, String.valueOf(jre.getJdkPreferenceIndex()));
+ addInteger(INITIAL_HEAP_SIZE, jre.getInitialHeapSize());
+ addInteger(INITIAL_HEAP_PERCENT, jre.getInitialHeapPercent());
+ addInteger(MAX_HEAP_SIZE, jre.getMaxHeapSize());
+ addInteger(MAX_HEAP_PERCENT, jre.getMaxHeapPercent());
+
+ StringBuffer options = new StringBuffer();
+ if (jre.getOptions() != null && !jre.getOptions().isEmpty()) {
+ addSpace(options);
+ append(options, jre.getOptions(), " ");
+ }
+ addText(JVM_OPTIONS, options.toString());
+ }
+
+ private void addSplash(Splash splash) {
+ if (splash == null) {
+ return;
+ }
+ addTrue(SHOW_SPLASH, true);
+ addTrue(SPLASH_WAITS_FOR_WINDOW, splash.getWaitForWindow());
+ addText(SPLASH_TIMEOUT, String.valueOf(splash.getTimeout()));
+ addTrue(SPLASH_TIMEOUT_ERR, splash.isTimeoutErr());
+ addBitmap(SPLASH_BITMAP, splash.getFile());
+ }
+
+ private void addMessages(Config c) {
+ Msg msg = c.getMessages();
+ if (msg == null) {
+ msg = new Msg();
+ }
+ addText(STARTUP_ERR, msg.getStartupErr());
+ addText(BUNDLED_JRE_ERR, msg.getBundledJreErr());
+ addText(JRE_VERSION_ERR, msg.getJreVersionErr());
+ addText(LAUNCHER_ERR, msg.getLauncherErr());
+ if (c.getSingleInstance() != null) {
+ addText(INSTANCE_ALREADY_EXISTS_MSG, msg.getInstanceAlreadyExistsMsg());
+ }
+ }
+
+ private void append(StringBuffer sb, List list, String separator) {
+ for (int i = 0; i < list.size(); i++) {
+ sb.append(list.get(i));
+ if (i < list.size() - 1) {
+ sb.append(separator);
+ }
+ }
+ }
+
+ private void addText(int id, String text) {
+ if (text == null || text.equals("")) {
+ return;
+ }
+ _sb.append(id);
+ _sb.append(" RCDATA BEGIN \"");
+ _sb.append(escape(text));
+ _sb.append("\\0\" END\n");
+ }
+
+ private void addTrue(int id, boolean value) {
+ if (value) {
+ addText(id, "true");
+ }
+ }
+
+ private void addInteger(int id, Integer value) {
+ if (value != null) {
+ addText(id, value.toString());
+ }
+ }
+
+ /**
+ * Stores path in Windows format with '\' separators.
+ */
+ private void addWindowsPath(int id, String path) {
+ if (path == null || path.equals("")) {
+ return;
+ }
+ _sb.append(id);
+ _sb.append(" RCDATA BEGIN \"");
+ _sb.append(path.replaceAll("\\\\", "\\\\\\\\")
+ .replaceAll("/", "\\\\\\\\"));
+ _sb.append("\\0\" END\n");
+ }
+
+ private void addManifest(int id, File manifest) {
+ if (manifest == null || manifest.getPath().equals("")) {
+ return;
+ }
+ _sb.append(id);
+ _sb.append(" 24 \"");
+ _sb.append(getPath(Util.getAbsoluteFile(
+ ConfigPersister.getInstance().getConfigPath(), manifest)));
+ _sb.append("\"\n");
+ }
+
+ private void addIcon(int id, File icon) {
+ if (icon == null || icon.getPath().equals("")) {
+ return;
+ }
+ _sb.append(id);
+ _sb.append(" ICON DISCARDABLE \"");
+ _sb.append(getPath(Util.getAbsoluteFile(
+ ConfigPersister.getInstance().getConfigPath(), icon)));
+ _sb.append("\"\n");
+ }
+
+ private void addBitmap(int id, File bitmap) {
+ if (bitmap == null) {
+ return;
+ }
+ _sb.append(id);
+ _sb.append(" BITMAP \"");
+ _sb.append(getPath(Util.getAbsoluteFile(
+ ConfigPersister.getInstance().getConfigPath(), bitmap)));
+ _sb.append("\"\n");
+ }
+
+ private String getPath(File f) {
+ return f.getPath().replaceAll("\\\\", "\\\\\\\\");
+ }
+
+ private void addSpace(StringBuffer sb) {
+ int len = sb.length();
+ if (len-- > 0 && sb.charAt(len) != ' ') {
+ sb.append(' ');
+ }
+ }
+
+ private void addVerBlockValue(String key, String value) {
+ _sb.append(" VALUE \"");
+ _sb.append(key);
+ _sb.append("\", \"");
+ if (value != null) {
+ _sb.append(escape(value));
+ }
+ _sb.append("\"\n");
+ }
+
+ private String escape(String text) {
+ return text.replaceAll("\"", "\"\"");
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/Util.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/Util.java
new file mode 100755
index 000000000..f3bf2456d
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/Util.java
@@ -0,0 +1,197 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on 2005-04-24
+ */
+package net.sf.launch4j;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.Writer;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * @author Copyright (C) 2005 Grzegorz Kowal
+ */
+public class Util {
+ public static final boolean WINDOWS_OS = System.getProperty("os.name")
+ .toLowerCase().startsWith("windows");
+
+ private Util() {}
+
+ public static File createTempFile(String suffix) throws IOException {
+ String tmpdir = System.getProperty("launch4j.tmpdir");
+ if (tmpdir != null) {
+ if (tmpdir.indexOf(' ') != -1) {
+ throw new IOException(Messages.getString("Util.tmpdir"));
+ }
+ return File.createTempFile("launch4j", suffix, new File(tmpdir));
+ } else {
+ return File.createTempFile("launch4j", suffix);
+ }
+ }
+
+ /**
+ * Returns the base directory of a jar file or null if the class is a standalone file.
+ * @return System specific path
+ *
+ * Based on a patch submitted by Josh Elsasser
+ */
+ public static File getJarBasedir() {
+ String url = Util.class.getClassLoader()
+ .getResource(Util.class.getName().replace('.', '/') + ".class")
+ .getFile()
+ .replaceAll("%20", " ");
+ if (url.startsWith("file:")) {
+ String jar = url.substring(5, url.lastIndexOf('!'));
+ int x = jar.lastIndexOf('/');
+ if (x == -1) {
+ x = jar.lastIndexOf('\\');
+ }
+ String basedir = jar.substring(0, x + 1);
+ return new File(basedir);
+ } else {
+ return new File(".");
+ }
+ }
+
+ public static File getAbsoluteFile(File basepath, File f) {
+ return f.isAbsolute() ? f : new File(basepath, f.getPath());
+ }
+
+ public static String getExtension(File f) {
+ String name = f.getName();
+ int x = name.lastIndexOf('.');
+ if (x != -1) {
+ return name.substring(x);
+ } else {
+ return "";
+ }
+ }
+
+ public static void exec(String[] cmd, Log log) throws ExecException {
+ BufferedReader is = null;
+ try {
+ if (WINDOWS_OS) {
+ for (int i = 0; i < cmd.length; i++) {
+ cmd[i] = cmd[i].replaceAll("/", "\\\\");
+ }
+ }
+ Process p = Runtime.getRuntime().exec(cmd);
+ is = new BufferedReader(new InputStreamReader(p.getErrorStream()));
+ String line;
+ int errLine = -1;
+ Pattern pattern = Pattern.compile(":\\d+:");
+ while ((line = is.readLine()) != null) {
+ log.append(line);
+ Matcher matcher = pattern.matcher(line);
+ if (matcher.find()) {
+ errLine = Integer.valueOf(
+ line.substring(matcher.start() + 1, matcher.end() - 1))
+ .intValue();
+ if (line.matches("(?i).*unrecognized escape sequence")) {
+ log.append(Messages.getString("Util.use.double.backslash"));
+ }
+ break;
+ }
+ }
+ is.close();
+ p.waitFor();
+ if (errLine != -1) {
+ throw new ExecException(Messages.getString("Util.exec.failed")
+ + ": " + cmd, errLine);
+ }
+ if (p.exitValue() != 0) {
+ throw new ExecException(Messages.getString("Util.exec.failed")
+ + "(" + p.exitValue() + "): " + cmd);
+ }
+ } catch (IOException e) {
+ close(is);
+ throw new ExecException(e);
+ } catch (InterruptedException e) {
+ close(is);
+ throw new ExecException(e);
+ }
+ }
+
+ public static void close(final InputStream o) {
+ if (o != null) {
+ try {
+ o.close();
+ } catch (IOException e) {
+ System.err.println(e); // XXX log
+ }
+ }
+ }
+
+ public static void close(final OutputStream o) {
+ if (o != null) {
+ try {
+ o.close();
+ } catch (IOException e) {
+ System.err.println(e); // XXX log
+ }
+ }
+ }
+
+ public static void close(final Reader o) {
+ if (o != null) {
+ try {
+ o.close();
+ } catch (IOException e) {
+ System.err.println(e); // XXX log
+ }
+ }
+ }
+
+ public static void close(final Writer o) {
+ if (o != null) {
+ try {
+ o.close();
+ } catch (IOException e) {
+ System.err.println(e); // XXX log
+ }
+ }
+ }
+
+ public static boolean delete(File f) {
+ return (f != null) ? f.delete() : false;
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/ant/AntClassPath.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/ant/AntClassPath.java
new file mode 100755
index 000000000..a67bab91f
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/ant/AntClassPath.java
@@ -0,0 +1,61 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on Jul 19, 2006
+ */
+package net.sf.launch4j.ant;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import net.sf.launch4j.config.ClassPath;
+
+/**
+ * @author Copyright (C) 2006 Grzegorz Kowal
+ */
+public class AntClassPath extends ClassPath {
+ private final List wrappedPaths = new ArrayList();
+
+ public void setCp(String cp){
+ wrappedPaths.add(cp);
+ }
+
+ public void addCp(StringWrapper cp) {
+ wrappedPaths.add(cp);
+ }
+
+ public void unwrap() {
+ setPaths(StringWrapper.unwrap(wrappedPaths));
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/ant/AntConfig.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/ant/AntConfig.java
new file mode 100755
index 000000000..4482436a9
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/ant/AntConfig.java
@@ -0,0 +1,129 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on May 24, 2005
+ */
+package net.sf.launch4j.ant;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.tools.ant.BuildException;
+
+import net.sf.launch4j.config.Config;
+import net.sf.launch4j.config.Msg;
+import net.sf.launch4j.config.SingleInstance;
+import net.sf.launch4j.config.Splash;
+import net.sf.launch4j.config.VersionInfo;
+
+/**
+ * @author Copyright (C) 2005 Grzegorz Kowal
+ */
+public class AntConfig extends Config {
+ private final List wrappedHeaderObjects = new ArrayList();
+ private final List wrappedLibs = new ArrayList();
+ private final List wrappedVariables = new ArrayList();
+
+ public void setJarPath(String path) {
+ setJar(new File(path));
+ }
+
+ public void addObj(StringWrapper obj) {
+ wrappedHeaderObjects.add(obj);
+ }
+
+ public void addLib(StringWrapper lib) {
+ wrappedLibs.add(lib);
+ }
+
+ public void addVar(StringWrapper var) {
+ wrappedVariables.add(var);
+ }
+
+ // __________________________________________________________________________________
+
+ public void addSingleInstance(SingleInstance singleInstance) {
+ checkNull(getSingleInstance(), "singleInstance");
+ setSingleInstance(singleInstance);
+ }
+
+ public void addClassPath(AntClassPath classPath) {
+ checkNull(getClassPath(), "classPath");
+ setClassPath(classPath);
+ }
+
+ public void addJre(AntJre jre) {
+ checkNull(getJre(), "jre");
+ setJre(jre);
+ }
+
+ public void addSplash(Splash splash) {
+ checkNull(getSplash(), "splash");
+ setSplash(splash);
+ }
+
+ public void addVersionInfo(VersionInfo versionInfo) {
+ checkNull(getVersionInfo(), "versionInfo");
+ setVersionInfo(versionInfo);
+ }
+
+ public void addMessages(Msg messages) {
+ checkNull(getMessages(), "messages");
+ setMessages(messages);
+ }
+
+ // __________________________________________________________________________________
+
+ public void unwrap() {
+ setHeaderObjects(StringWrapper.unwrap(wrappedHeaderObjects));
+ setLibs(StringWrapper.unwrap(wrappedLibs));
+ setVariables(StringWrapper.unwrap(wrappedVariables));
+ if (getClassPath() != null) {
+ ((AntClassPath) getClassPath()).unwrap();
+ }
+ if (getJre() != null) {
+ ((AntJre) getJre()).unwrap();
+ }
+ }
+
+ private void checkNull(Object o, String name) {
+ if (o != null) {
+ throw new BuildException(
+ Messages.getString("AntConfig.duplicate.element")
+ + ": "
+ + name);
+ }
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/ant/AntJre.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/ant/AntJre.java
new file mode 100755
index 000000000..b83e3ee02
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/ant/AntJre.java
@@ -0,0 +1,69 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on Jul 18, 2006
+ */
+package net.sf.launch4j.ant;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import net.sf.launch4j.config.Jre;
+
+/**
+ * @author Copyright (C) 2006 Grzegorz Kowal
+ */
+public class AntJre extends Jre {
+ private final List wrappedOptions = new ArrayList();
+
+ public void addOpt(StringWrapper opt) {
+ wrappedOptions.add(opt);
+ }
+
+ public void unwrap() {
+ setOptions(StringWrapper.unwrap(wrappedOptions));
+ }
+
+ /**
+ * For backwards compatibility.
+ */
+ public void setDontUsePrivateJres(boolean dontUse) {
+ if (dontUse) {
+ setJdkPreference(JDK_PREFERENCE_JRE_ONLY);
+ }
+ else {
+ setJdkPreference(JDK_PREFERENCE_PREFER_JRE);
+ }
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/ant/Launch4jTask.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/ant/Launch4jTask.java
new file mode 100755
index 000000000..a28287698
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/ant/Launch4jTask.java
@@ -0,0 +1,162 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on May 24, 2005
+ */
+package net.sf.launch4j.ant;
+
+import java.io.File;
+
+import net.sf.launch4j.Builder;
+import net.sf.launch4j.BuilderException;
+import net.sf.launch4j.Log;
+import net.sf.launch4j.config.Config;
+import net.sf.launch4j.config.ConfigPersister;
+import net.sf.launch4j.config.ConfigPersisterException;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+
+/**
+ * @author Copyright (C) 2005 Grzegorz Kowal
+ */
+public class Launch4jTask extends Task {
+ private File _configFile;
+ private AntConfig _config;
+
+ // System properties
+ private File tmpdir; // launch4j.tmpdir
+ private File bindir; // launch4j.bindir
+
+ // Override configFile settings
+ private File jar;
+ private File outfile;
+ private String fileVersion;
+ private String txtFileVersion;
+ private String productVersion;
+ private String txtProductVersion;
+
+ public void execute() throws BuildException {
+ try {
+ if (tmpdir != null) {
+ System.setProperty("launch4j.tmpdir", tmpdir.getPath());
+ }
+ if (bindir != null) {
+ System.setProperty("launch4j.bindir", bindir.getPath());
+ }
+ if (_configFile != null && _config != null) {
+ throw new BuildException(
+ Messages.getString("Launch4jTask.specify.config"));
+ } else if (_configFile != null) {
+ ConfigPersister.getInstance().load(_configFile);
+ Config c = ConfigPersister.getInstance().getConfig();
+ if (jar != null) {
+ c.setJar(jar);
+ }
+ if (outfile != null) {
+ c.setOutfile(outfile);
+ }
+ if (fileVersion != null) {
+ c.getVersionInfo().setFileVersion(fileVersion);
+ }
+ if (txtFileVersion != null) {
+ c.getVersionInfo().setTxtFileVersion(txtFileVersion);
+ }
+ if (productVersion != null) {
+ c.getVersionInfo().setProductVersion(productVersion);
+ }
+ if (txtProductVersion != null) {
+ c.getVersionInfo().setTxtProductVersion(txtProductVersion);
+ }
+ } else if (_config != null) {
+ _config.unwrap();
+ ConfigPersister.getInstance().setAntConfig(_config,
+ getProject().getBaseDir());
+ } else {
+ throw new BuildException(
+ Messages.getString("Launch4jTask.specify.config"));
+ }
+ final Builder b = new Builder(Log.getAntLog());
+ b.build();
+ } catch (ConfigPersisterException e) {
+ throw new BuildException(e);
+ } catch (BuilderException e) {
+ throw new BuildException(e);
+ }
+ }
+
+ public void setConfigFile(File configFile) {
+ _configFile = configFile;
+ }
+
+ public void addConfig(AntConfig config) {
+ _config = config;
+ }
+
+ public void setBindir(File bindir) {
+ this.bindir = bindir;
+ }
+
+ public void setTmpdir(File tmpdir) {
+ this.tmpdir = tmpdir;
+ }
+
+ public void setFileVersion(String fileVersion) {
+ this.fileVersion = fileVersion;
+ }
+
+ public void setJar(File jar) {
+ this.jar = jar;
+ }
+
+ public void setJarPath(String path) {
+ this.jar = new File(path);
+ }
+
+ public void setOutfile(File outfile) {
+ this.outfile = outfile;
+ }
+
+ public void setProductVersion(String productVersion) {
+ this.productVersion = productVersion;
+ }
+
+ public void setTxtFileVersion(String txtFileVersion) {
+ this.txtFileVersion = txtFileVersion;
+ }
+
+ public void setTxtProductVersion(String txtProductVersion) {
+ this.txtProductVersion = txtProductVersion;
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/ant/Messages.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/ant/Messages.java
new file mode 100755
index 000000000..0f823f7af
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/ant/Messages.java
@@ -0,0 +1,55 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package net.sf.launch4j.ant;
+
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+public class Messages {
+ private static final String BUNDLE_NAME = "net.sf.launch4j.ant.messages";
+
+ private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle
+ .getBundle(BUNDLE_NAME);
+
+ private Messages() {
+ }
+
+ public static String getString(String key) {
+ try {
+ return RESOURCE_BUNDLE.getString(key);
+ } catch (MissingResourceException e) {
+ return '!' + key + '!';
+ }
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/ant/StringWrapper.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/ant/StringWrapper.java
new file mode 100755
index 000000000..6d38af1a5
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/ant/StringWrapper.java
@@ -0,0 +1,67 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on Jul 18, 2006
+ */
+package net.sf.launch4j.ant;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * @author Copyright (C) 2006 Grzegorz Kowal
+ */
+public class StringWrapper {
+ private String text;
+
+ public static List unwrap(List wrappers) {
+ if (wrappers.isEmpty()) {
+ return null;
+ }
+ List strings = new ArrayList(wrappers.size());
+ for (Iterator iter = wrappers.iterator(); iter.hasNext();) {
+ strings.add(iter.next().toString());
+ }
+ return strings;
+ }
+
+ public void addText(String text) {
+ this.text = text;
+ }
+
+ public String toString() {
+ return text;
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/ant/messages.properties b/build/windows/launcher/launch4j/src/net/sf/launch4j/ant/messages.properties
new file mode 100755
index 000000000..9666633c2
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/ant/messages.properties
@@ -0,0 +1,35 @@
+#
+# Launch4j (http://launch4j.sourceforge.net/)
+# Cross-platform Java application wrapper for creating Windows native executables.
+#
+# Copyright (c) 2004, 2007 Grzegorz Kowal
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification,
+# are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+# * Neither the name of the Launch4j nor the names of its contributors
+# may be used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+Launch4jTask.specify.config=Specify configFile or config
+AntConfig.duplicate.element=Duplicate element
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/ant/messages_es.properties b/build/windows/launcher/launch4j/src/net/sf/launch4j/ant/messages_es.properties
new file mode 100755
index 000000000..9211e8e03
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/ant/messages_es.properties
@@ -0,0 +1,35 @@
+#
+# Launch4j (http://launch4j.sourceforge.net/)
+# Cross-platform Java application wrapper for creating Windows native executables.
+#
+# Copyright (c) 2004, 2007 Grzegorz Kowal, Patricio Martínez Ros
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification,
+# are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+# * Neither the name of the Launch4j nor the names of its contributors
+# may be used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+Launch4jTask.specify.config=Specify configFile or config
+AntConfig.duplicate.element=Duplicate element
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/Binding.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/Binding.java
new file mode 100755
index 000000000..49c9b45ff
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/Binding.java
@@ -0,0 +1,62 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on Apr 30, 2005
+ */
+package net.sf.launch4j.binding;
+
+import java.awt.Color;
+
+/**
+ * @author Copyright (C) 2005 Grzegorz Kowal
+ */
+public interface Binding {
+ /** Used to mark components with invalid data. */
+ public final static Color INVALID_COLOR = Color.PINK;
+
+ /** Java Bean property bound to a component */
+ public String getProperty();
+ /** Clear component, set it to the default value */
+ public void clear(IValidatable bean);
+ /** Java Bean property -> Component */
+ public void put(IValidatable bean);
+ /** Component -> Java Bean property */
+ public void get(IValidatable bean);
+ /** Mark component as valid */
+ public void markValid();
+ /** Mark component as invalid */
+ public void markInvalid();
+ /** Enable or disable the component */
+ public void setEnabled(boolean enabled);
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/BindingException.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/BindingException.java
new file mode 100755
index 000000000..15dc10cc0
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/BindingException.java
@@ -0,0 +1,52 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on Apr 30, 2005
+ */
+package net.sf.launch4j.binding;
+
+/**
+ * Signals a runtime error, a missing property in a Java Bean for example.
+ *
+ * @author Copyright (C) 2005 Grzegorz Kowal
+ */
+public class BindingException extends RuntimeException {
+ public BindingException(Throwable t) {
+ super(t);
+ }
+
+ public BindingException(String msg) {
+ super(msg);
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/Bindings.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/Bindings.java
new file mode 100755
index 000000000..73f507e49
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/Bindings.java
@@ -0,0 +1,317 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on Apr 30, 2005
+ */
+package net.sf.launch4j.binding;
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+import javax.swing.JList;
+import javax.swing.JRadioButton;
+import javax.swing.JTextArea;
+import javax.swing.JToggleButton;
+import javax.swing.text.JTextComponent;
+
+import org.apache.commons.beanutils.PropertyUtils;
+
+/**
+ * Creates and handles bindings.
+ *
+ * @author Copyright (C) 2005 Grzegorz Kowal
+ */
+public class Bindings implements PropertyChangeListener {
+ private final Map _bindings = new HashMap();
+ private final Map _optComponents = new HashMap();
+ private boolean _modified = false;
+
+ /**
+ * Used to track component modifications.
+ */
+ public void propertyChange(PropertyChangeEvent evt) {
+ String prop = evt.getPropertyName();
+ if ("AccessibleValue".equals(prop)
+ || "AccessibleText".equals(prop)
+ || "AccessibleVisibleData".equals(prop)) {
+ _modified = true;
+ }
+ }
+
+ /**
+ * Any of the components modified?
+ */
+ public boolean isModified() {
+ return _modified;
+ }
+
+ public Binding getBinding(String property) {
+ return (Binding) _bindings.get(property);
+ }
+
+ private void registerPropertyChangeListener(JComponent c) {
+ c.getAccessibleContext().addPropertyChangeListener(this);
+ }
+
+ private void registerPropertyChangeListener(JComponent[] cs) {
+ for (int i = 0; i < cs.length; i++) {
+ cs[i].getAccessibleContext().addPropertyChangeListener(this);
+ }
+ }
+
+ private boolean isPropertyNull(IValidatable bean, Binding b) {
+ try {
+ for (Iterator iter = _optComponents.keySet().iterator(); iter.hasNext();) {
+ String property = (String) iter.next();
+ if (b.getProperty().startsWith(property)) {
+ return PropertyUtils.getProperty(bean, property) == null;
+ }
+ }
+ return false;
+ } catch (Exception e) {
+ throw new BindingException(e);
+ }
+ }
+
+ /**
+ * Enables or disables all components bound to properties that begin with given prefix.
+ */
+ public void setComponentsEnabled(String prefix, boolean enabled) {
+ for (Iterator iter = _bindings.values().iterator(); iter.hasNext();) {
+ Binding b = (Binding) iter.next();
+ if (b.getProperty().startsWith(prefix)) {
+ b.setEnabled(enabled);
+ }
+ }
+ }
+
+ /**
+ * Clear all components, set them to their default values.
+ * Clears the _modified flag.
+ */
+ public void clear(IValidatable bean) {
+ for (Iterator iter = _optComponents.values().iterator(); iter.hasNext();) {
+ ((Binding) iter.next()).clear(bean);
+ }
+ for (Iterator iter = _bindings.values().iterator(); iter.hasNext();) {
+ ((Binding) iter.next()).clear(bean);
+ }
+ _modified = false;
+ }
+
+ /**
+ * Copies data from the Java Bean to the UI components.
+ * Clears the _modified flag.
+ */
+ public void put(IValidatable bean) {
+ for (Iterator iter = _optComponents.values().iterator(); iter.hasNext();) {
+ ((Binding) iter.next()).put(bean);
+ }
+ for (Iterator iter = _bindings.values().iterator(); iter.hasNext();) {
+ Binding b = (Binding) iter.next();
+ if (isPropertyNull(bean, b)) {
+ b.clear(null);
+ } else {
+ b.put(bean);
+ }
+ }
+ _modified = false;
+ }
+
+ /**
+ * Copies data from UI components to the Java Bean and checks it's class invariants.
+ * Clears the _modified flag.
+ * @throws InvariantViolationException
+ * @throws BindingException
+ */
+ public void get(IValidatable bean) {
+ try {
+ for (Iterator iter = _optComponents.values().iterator(); iter.hasNext();) {
+ ((Binding) iter.next()).get(bean);
+ }
+ for (Iterator iter = _bindings.values().iterator(); iter.hasNext();) {
+ Binding b = (Binding) iter.next();
+ if (!isPropertyNull(bean, b)) {
+ b.get(bean);
+ }
+ }
+ bean.checkInvariants();
+ for (Iterator iter = _optComponents.keySet().iterator(); iter.hasNext();) {
+ String property = (String) iter.next();
+ IValidatable component = (IValidatable) PropertyUtils.getProperty(bean,
+ property);
+ if (component != null) {
+ component.checkInvariants();
+ }
+ }
+ _modified = false; // XXX
+ } catch (InvariantViolationException e) {
+ e.setBinding(getBinding(e.getProperty()));
+ throw e;
+ } catch (Exception e) {
+ throw new BindingException(e);
+ }
+ }
+
+ private Bindings add(Binding b) {
+ if (_bindings.containsKey(b.getProperty())) {
+ throw new BindingException(Messages.getString("Bindings.duplicate.binding"));
+ }
+ _bindings.put(b.getProperty(), b);
+ return this;
+ }
+
+ /**
+ * Add an optional (nullable) Java Bean component of type clazz.
+ */
+ public Bindings addOptComponent(String property, Class clazz, JToggleButton c,
+ boolean enabledByDefault) {
+ Binding b = new OptComponentBinding(this, property, clazz, c, enabledByDefault);
+ if (_optComponents.containsKey(property)) {
+ throw new BindingException(Messages.getString("Bindings.duplicate.binding"));
+ }
+ _optComponents.put(property, b);
+ return this;
+ }
+
+ /**
+ * Add an optional (nullable) Java Bean component of type clazz.
+ */
+ public Bindings addOptComponent(String property, Class clazz, JToggleButton c) {
+ return addOptComponent(property, clazz, c, false);
+ }
+
+ /**
+ * Handles JEditorPane, JTextArea, JTextField
+ */
+ public Bindings add(String property, JTextComponent c, String defaultValue) {
+ registerPropertyChangeListener(c);
+ return add(new JTextComponentBinding(property, c, defaultValue));
+ }
+
+ /**
+ * Handles JEditorPane, JTextArea, JTextField
+ */
+ public Bindings add(String property, JTextComponent c) {
+ registerPropertyChangeListener(c);
+ return add(new JTextComponentBinding(property, c, ""));
+ }
+
+ /**
+ * Handles JToggleButton, JCheckBox
+ */
+ public Bindings add(String property, JToggleButton c, boolean defaultValue) {
+ registerPropertyChangeListener(c);
+ return add(new JToggleButtonBinding(property, c, defaultValue));
+ }
+
+ /**
+ * Handles JToggleButton, JCheckBox
+ */
+ public Bindings add(String property, JToggleButton c) {
+ registerPropertyChangeListener(c);
+ return add(new JToggleButtonBinding(property, c, false));
+ }
+
+ /**
+ * Handles JRadioButton
+ */
+ public Bindings add(String property, JRadioButton[] cs, int defaultValue) {
+ registerPropertyChangeListener(cs);
+ return add(new JRadioButtonBinding(property, cs, defaultValue));
+ }
+
+ /**
+ * Handles JRadioButton
+ */
+ public Bindings add(String property, JRadioButton[] cs) {
+ registerPropertyChangeListener(cs);
+ return add(new JRadioButtonBinding(property, cs, 0));
+ }
+
+ /**
+ * Handles JTextArea
+ */
+ public Bindings add(String property, JTextArea textArea, String defaultValue) {
+ registerPropertyChangeListener(textArea);
+ return add(new JTextComponentBinding(property, textArea, defaultValue));
+ }
+
+ /**
+ * Handles JTextArea lists
+ */
+ public Bindings add(String property, JTextArea textArea) {
+ registerPropertyChangeListener(textArea);
+ return add(new JTextAreaBinding(property, textArea));
+ }
+
+ /**
+ * Handles Optional JTextArea lists
+ */
+ public Bindings add(String property, String stateProperty,
+ JToggleButton button, JTextArea textArea) {
+ registerPropertyChangeListener(button);
+ registerPropertyChangeListener(textArea);
+ return add(new OptJTextAreaBinding(property, stateProperty, button, textArea));
+ }
+
+ /**
+ * Handles JList
+ */
+ public Bindings add(String property, JList list) {
+ registerPropertyChangeListener(list);
+ return add(new JListBinding(property, list));
+ }
+
+ /**
+ * Handles JComboBox
+ */
+ public Bindings add(String property, JComboBox combo, int defaultValue) {
+ registerPropertyChangeListener(combo);
+ return add(new JComboBoxBinding(property, combo, defaultValue));
+ }
+
+ /**
+ * Handles JComboBox
+ */
+ public Bindings add(String property, JComboBox combo) {
+ registerPropertyChangeListener(combo);
+ return add(new JComboBoxBinding(property, combo, 0));
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/IValidatable.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/IValidatable.java
new file mode 100755
index 000000000..fe0dd4862
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/IValidatable.java
@@ -0,0 +1,44 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on 2004-01-30
+ */
+package net.sf.launch4j.binding;
+
+/**
+ * @author Copyright (C) 2004 Grzegorz Kowal
+ */
+public interface IValidatable {
+ public void checkInvariants();
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/InvariantViolationException.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/InvariantViolationException.java
new file mode 100755
index 000000000..2f7f88b1d
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/InvariantViolationException.java
@@ -0,0 +1,67 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on Jun 23, 2003
+ */
+package net.sf.launch4j.binding;
+
+/**
+ * @author Copyright (C) 2003 Grzegorz Kowal
+ */
+public class InvariantViolationException extends RuntimeException {
+ private final String _property;
+ private Binding _binding;
+
+ public InvariantViolationException(String msg) {
+ super(msg);
+ _property = null;
+ }
+
+ public InvariantViolationException(String property, String msg) {
+ super(msg);
+ _property = property;
+ }
+
+ public String getProperty() {
+ return _property;
+ }
+
+ public Binding getBinding() {
+ return _binding;
+ }
+
+ public void setBinding(Binding binding) {
+ _binding = binding;
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/JComboBoxBinding.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/JComboBoxBinding.java
new file mode 100755
index 000000000..81d6ff28e
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/JComboBoxBinding.java
@@ -0,0 +1,119 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2007 Ian Roberts
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on May 10, 2005
+ */
+package net.sf.launch4j.binding;
+
+import java.awt.Color;
+
+import javax.swing.JComboBox;
+
+import org.apache.commons.beanutils.PropertyUtils;
+
+/**
+ * @author Copyright (C) 2007 Ian Roberts
+ */
+public class JComboBoxBinding implements Binding {
+ private final String _property;
+ private final JComboBox _combo;
+ private final int _defaultValue;
+ private final Color _validColor;
+
+ public JComboBoxBinding(String property, JComboBox combo, int defaultValue) {
+ if (property == null || combo == null) {
+ throw new NullPointerException();
+ }
+ if (property.equals("")
+ || combo.getItemCount() == 0
+ || defaultValue < 0 || defaultValue >= combo.getItemCount()) {
+ throw new IllegalArgumentException();
+ }
+ _property = property;
+ _combo = combo;
+ _defaultValue = defaultValue;
+ _validColor = combo.getBackground();
+ }
+
+ public String getProperty() {
+ return _property;
+ }
+
+ public void clear(IValidatable bean) {
+ select(_defaultValue);
+ }
+
+ public void put(IValidatable bean) {
+ try {
+ Integer i = (Integer) PropertyUtils.getProperty(bean, _property);
+ if (i == null) {
+ throw new BindingException(
+ Messages.getString("JComboBoxBinding.property.null"));
+ }
+ select(i.intValue());
+ } catch (Exception e) {
+ throw new BindingException(e);
+ }
+ }
+
+ public void get(IValidatable bean) {
+ try {
+ PropertyUtils.setProperty(bean, _property, new Integer(_combo.getSelectedIndex()));
+ return;
+ } catch (Exception e) {
+ throw new BindingException(e);
+ }
+ }
+
+ private void select(int index) {
+ if (index < 0 || index >= _combo.getItemCount()) {
+ throw new BindingException(
+ Messages.getString("JComboBoxBinding.index.out.of.bounds"));
+ }
+ _combo.setSelectedIndex(index);
+ }
+
+ public void markValid() {
+ _combo.setBackground(_validColor);
+ _combo.requestFocusInWindow();
+ }
+
+ public void markInvalid() {
+ _combo.setBackground(Binding.INVALID_COLOR);
+ }
+
+ public void setEnabled(boolean enabled) {
+ _combo.setEnabled(enabled);
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/JListBinding.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/JListBinding.java
new file mode 100755
index 000000000..31dec58c1
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/JListBinding.java
@@ -0,0 +1,118 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on May 1, 2006
+ */
+package net.sf.launch4j.binding;
+
+import java.awt.Color;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.swing.DefaultListModel;
+import javax.swing.JList;
+
+import org.apache.commons.beanutils.PropertyUtils;
+
+/**
+ * @author Copyright (C) 2006 Grzegorz Kowal
+ */
+public class JListBinding implements Binding {
+ private final String _property;
+ private final JList _list;
+ private final Color _validColor;
+
+ public JListBinding(String property, JList list) {
+ if (property == null || list == null) {
+ throw new NullPointerException();
+ }
+ if (property.equals("")) {
+ throw new IllegalArgumentException();
+ }
+ _property = property;
+ _list = list;
+ _validColor = _list.getBackground();
+ }
+
+ public String getProperty() {
+ return _property;
+ }
+
+ public void clear(IValidatable bean) {
+ _list.setModel(new DefaultListModel());
+ }
+
+ public void put(IValidatable bean) {
+ try {
+ DefaultListModel model = new DefaultListModel();
+ List list = (List) PropertyUtils.getProperty(bean, _property);
+ if (list != null) {
+ for (Iterator iter = list.iterator(); iter.hasNext();) {
+ model.addElement(iter.next());
+ }
+ }
+ _list.setModel(model);
+ } catch (Exception e) {
+ throw new BindingException(e);
+ }
+ }
+
+ public void get(IValidatable bean) {
+ try {
+ DefaultListModel model = (DefaultListModel) _list.getModel();
+ final int size = model.getSize();
+ List list = new ArrayList(size);
+ for (int i = 0; i < size; i++) {
+ list.add(model.get(i));
+ }
+ PropertyUtils.setProperty(bean, _property, list);
+ } catch (Exception e) {
+ throw new BindingException(e);
+ }
+ }
+
+ public void markValid() {
+ _list.setBackground(_validColor);
+ _list.requestFocusInWindow();
+ }
+
+ public void markInvalid() {
+ _list.setBackground(Binding.INVALID_COLOR);
+ }
+
+ public void setEnabled(boolean enabled) {
+ _list.setEnabled(enabled);
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/JRadioButtonBinding.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/JRadioButtonBinding.java
new file mode 100755
index 000000000..9d922bedf
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/JRadioButtonBinding.java
@@ -0,0 +1,146 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on May 10, 2005
+ */
+package net.sf.launch4j.binding;
+
+import java.awt.Color;
+
+import javax.swing.JRadioButton;
+
+import org.apache.commons.beanutils.PropertyUtils;
+
+/**
+ * @author Copyright (C) 2005 Grzegorz Kowal
+ */
+public class JRadioButtonBinding implements Binding {
+ private final String _property;
+ private final JRadioButton[] _buttons;
+ private final int _defaultValue;
+ private final Color _validColor;
+
+ public JRadioButtonBinding(String property, JRadioButton[] buttons, int defaultValue) {
+ if (property == null || buttons == null) {
+ throw new NullPointerException();
+ }
+ for (int i = 0; i < buttons.length; i++) {
+ if (buttons[i] == null) {
+ throw new NullPointerException();
+ }
+ }
+ if (property.equals("")
+ || buttons.length == 0
+ || defaultValue < 0 || defaultValue >= buttons.length) {
+ throw new IllegalArgumentException();
+ }
+ _property = property;
+ _buttons = buttons;
+ _defaultValue = defaultValue;
+ _validColor = buttons[0].getBackground();
+ }
+
+ public String getProperty() {
+ return _property;
+ }
+
+ public void clear(IValidatable bean) {
+ select(_defaultValue);
+ }
+
+ public void put(IValidatable bean) {
+ try {
+ Integer i = (Integer) PropertyUtils.getProperty(bean, _property);
+ if (i == null) {
+ throw new BindingException(
+ Messages.getString("JRadioButtonBinding.property.null"));
+ }
+ select(i.intValue());
+ } catch (Exception e) {
+ throw new BindingException(e);
+ }
+ }
+
+ public void get(IValidatable bean) {
+ try {
+ for (int i = 0; i < _buttons.length; i++) {
+ if (_buttons[i].isSelected()) {
+ PropertyUtils.setProperty(bean, _property, new Integer(i));
+ return;
+ }
+ }
+ throw new BindingException(
+ Messages.getString("JRadioButtonBinding.nothing.selected"));
+ } catch (Exception e) {
+ throw new BindingException(e);
+ }
+ }
+
+ private void select(int index) {
+ if (index < 0 || index >= _buttons.length) {
+ throw new BindingException(
+ Messages.getString("JRadioButtonBinding.index.out.of.bounds"));
+ }
+ _buttons[index].setSelected(true);
+ }
+
+ public void markValid() {
+ for (int i = 0; i < _buttons.length; i++) {
+ if (_buttons[i].isSelected()) {
+ _buttons[i].setBackground(_validColor);
+ _buttons[i].requestFocusInWindow();
+ return;
+ }
+ }
+ throw new BindingException(
+ Messages.getString("JRadioButtonBinding.nothing.selected"));
+ }
+
+ public void markInvalid() {
+ for (int i = 0; i < _buttons.length; i++) {
+ if (_buttons[i].isSelected()) {
+ _buttons[i].setBackground(Binding.INVALID_COLOR);
+ return;
+ }
+ }
+ throw new BindingException(
+ Messages.getString("JRadioButtonBinding.nothing.selected"));
+ }
+
+ public void setEnabled(boolean enabled) {
+ for (int i = 0; i < _buttons.length; i++) {
+ _buttons[i].setEnabled(enabled);
+ }
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/JTextAreaBinding.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/JTextAreaBinding.java
new file mode 100755
index 000000000..d4e8a2c65
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/JTextAreaBinding.java
@@ -0,0 +1,123 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on Jun 14, 2006
+ */
+package net.sf.launch4j.binding;
+
+import java.awt.Color;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.JTextArea;
+
+import org.apache.commons.beanutils.PropertyUtils;
+
+/**
+ * @author Copyright (C) 2006 Grzegorz Kowal
+ */
+public class JTextAreaBinding implements Binding {
+ private final String _property;
+ private final JTextArea _textArea;
+ private final Color _validColor;
+
+ public JTextAreaBinding(String property, JTextArea textArea) {
+ if (property == null || textArea == null) {
+ throw new NullPointerException();
+ }
+ if (property.equals("")) {
+ throw new IllegalArgumentException();
+ }
+ _property = property;
+ _textArea = textArea;
+ _validColor = _textArea.getBackground();
+ }
+
+ public String getProperty() {
+ return _property;
+ }
+
+ public void clear(IValidatable bean) {
+ put(bean);
+ }
+
+ public void put(IValidatable bean) {
+ try {
+ List list = (List) PropertyUtils.getProperty(bean, _property);
+ StringBuffer sb = new StringBuffer();
+ if (list != null) {
+ for (int i = 0; i < list.size(); i++) {
+ sb.append(list.get(i));
+ if (i < list.size() - 1) {
+ sb.append("\n");
+ }
+ }
+ }
+ _textArea.setText(sb.toString());
+ } catch (Exception e) {
+ throw new BindingException(e);
+ }
+ }
+
+ public void get(IValidatable bean) {
+ try {
+ String text = _textArea.getText();
+ if (!text.equals("")) {
+ String[] items = text.split("\n");
+ List list = new ArrayList();
+ for (int i = 0; i < items.length; i++) {
+ list.add(items[i]);
+ }
+ PropertyUtils.setProperty(bean, _property, list);
+ } else {
+ PropertyUtils.setProperty(bean, _property, null);
+ }
+ } catch (Exception e) {
+ throw new BindingException(e);
+ }
+ }
+
+ public void markValid() {
+ _textArea.setBackground(_validColor);
+ _textArea.requestFocusInWindow();
+ }
+
+ public void markInvalid() {
+ _textArea.setBackground(Binding.INVALID_COLOR);
+ }
+
+ public void setEnabled(boolean enabled) {
+ _textArea.setEnabled(enabled);
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/JTextComponentBinding.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/JTextComponentBinding.java
new file mode 100755
index 000000000..6b0dd1b0b
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/JTextComponentBinding.java
@@ -0,0 +1,108 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on Apr 30, 2005
+ */
+package net.sf.launch4j.binding;
+
+import java.awt.Color;
+
+import javax.swing.text.JTextComponent;
+
+import org.apache.commons.beanutils.BeanUtils;
+
+/**
+ * Handles JEditorPane, JTextArea, JTextField
+ *
+ * @author Copyright (C) 2005 Grzegorz Kowal
+ */
+public class JTextComponentBinding implements Binding {
+ private final String _property;
+ private final JTextComponent _textComponent;
+ private final String _defaultValue;
+ private final Color _validColor;
+
+ public JTextComponentBinding(String property, JTextComponent textComponent,
+ String defaultValue) {
+ if (property == null || textComponent == null || defaultValue == null) {
+ throw new NullPointerException();
+ }
+ if (property.equals("")) {
+ throw new IllegalArgumentException();
+ }
+ _property = property;
+ _textComponent = textComponent;
+ _defaultValue = defaultValue;
+ _validColor = _textComponent.getBackground();
+ }
+
+ public String getProperty() {
+ return _property;
+ }
+
+ public void clear(IValidatable bean) {
+ _textComponent.setText(_defaultValue);
+ }
+
+ public void put(IValidatable bean) {
+ try {
+ String s = BeanUtils.getProperty(bean, _property);
+ // XXX displays zeros as blank
+ _textComponent.setText(s != null && !s.equals("0") ? s : "");
+ } catch (Exception e) {
+ throw new BindingException(e);
+ }
+ }
+
+ public void get(IValidatable bean) {
+ try {
+ BeanUtils.setProperty(bean, _property, _textComponent.getText());
+ } catch (Exception e) {
+ throw new BindingException(e);
+ }
+ }
+
+ public void markValid() {
+ _textComponent.setBackground(_validColor);
+ _textComponent.requestFocusInWindow();
+ }
+
+ public void markInvalid() {
+ _textComponent.setBackground(Binding.INVALID_COLOR);
+ }
+
+ public void setEnabled(boolean enabled) {
+ _textComponent.setEnabled(enabled);
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/JToggleButtonBinding.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/JToggleButtonBinding.java
new file mode 100755
index 000000000..a7055cccc
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/JToggleButtonBinding.java
@@ -0,0 +1,108 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on Apr 30, 2005
+ */
+package net.sf.launch4j.binding;
+
+import java.awt.Color;
+
+import javax.swing.JToggleButton;
+
+import org.apache.commons.beanutils.PropertyUtils;
+
+/**
+ * Handles JToggleButton, JCheckBox
+ *
+ * @author Copyright (C) 2005 Grzegorz Kowal
+ */
+public class JToggleButtonBinding implements Binding {
+ private final String _property;
+ private final JToggleButton _button;
+ private final boolean _defaultValue;
+ private final Color _validColor;
+
+ public JToggleButtonBinding(String property, JToggleButton button,
+ boolean defaultValue) {
+ if (property == null || button == null) {
+ throw new NullPointerException();
+ }
+ if (property.equals("")) {
+ throw new IllegalArgumentException();
+ }
+ _property = property;
+ _button = button;
+ _defaultValue = defaultValue;
+ _validColor = _button.getBackground();
+ }
+
+ public String getProperty() {
+ return _property;
+ }
+
+ public void clear(IValidatable bean) {
+ _button.setSelected(_defaultValue);
+ }
+
+ public void put(IValidatable bean) {
+ try {
+ Boolean b = (Boolean) PropertyUtils.getProperty(bean, _property);
+ _button.setSelected(b != null && b.booleanValue());
+ } catch (Exception e) {
+ throw new BindingException(e);
+ }
+ }
+
+ public void get(IValidatable bean) {
+ try {
+ PropertyUtils.setProperty(bean, _property,
+ Boolean.valueOf(_button.isSelected()));
+ } catch (Exception e) {
+ throw new BindingException(e);
+ }
+ }
+
+ public void markValid() {
+ _button.setBackground(_validColor);
+ _button.requestFocusInWindow();
+ }
+
+ public void markInvalid() {
+ _button.setBackground(Binding.INVALID_COLOR);
+ }
+
+ public void setEnabled(boolean enabled) {
+ _button.setEnabled(enabled);
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/Messages.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/Messages.java
new file mode 100755
index 000000000..91ddff2b1
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/Messages.java
@@ -0,0 +1,78 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package net.sf.launch4j.binding;
+
+import java.text.MessageFormat;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+public class Messages {
+ private static final String BUNDLE_NAME = "net.sf.launch4j.binding.messages";
+
+ private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle
+ .getBundle(BUNDLE_NAME);
+ private static final MessageFormat FORMATTER = new MessageFormat("");
+
+ private Messages() {
+ }
+
+ public static String getString(String key) {
+ try {
+ return RESOURCE_BUNDLE.getString(key);
+ } catch (MissingResourceException e) {
+ return '!' + key + '!';
+ }
+ }
+
+ public static String getString(String key, String arg0) {
+ return getString(key, new Object[] {arg0});
+ }
+
+ public static String getString(String key, String arg0, String arg1) {
+ return getString(key, new Object[] {arg0, arg1});
+ }
+
+ public static String getString(String key, String arg0, String arg1, String arg2) {
+ return getString(key, new Object[] {arg0, arg1, arg2});
+ }
+
+ public static String getString(String key, Object[] args) {
+ try {
+ FORMATTER.applyPattern(RESOURCE_BUNDLE.getString(key));
+ return FORMATTER.format(args);
+ } catch (MissingResourceException e) {
+ return '!' + key + '!';
+ }
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/OptComponentBinding.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/OptComponentBinding.java
new file mode 100755
index 000000000..b573da628
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/OptComponentBinding.java
@@ -0,0 +1,119 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on May 11, 2005
+ */
+package net.sf.launch4j.binding;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.Arrays;
+
+import javax.swing.JToggleButton;
+
+import org.apache.commons.beanutils.PropertyUtils;
+
+/**
+ * @author Copyright (C) 2005 Grzegorz Kowal
+ */
+public class OptComponentBinding implements Binding, ActionListener {
+ private final Bindings _bindings;
+ private final String _property;
+ private final Class _clazz;
+ private final JToggleButton _button;
+ private final boolean _enabledByDefault;
+
+ public OptComponentBinding(Bindings bindings, String property, Class clazz,
+ JToggleButton button, boolean enabledByDefault) {
+ if (property == null || clazz == null || button == null) {
+ throw new NullPointerException();
+ }
+ if (property.equals("")) {
+ throw new IllegalArgumentException();
+ }
+ if (!Arrays.asList(clazz.getInterfaces()).contains(IValidatable.class)) {
+ throw new IllegalArgumentException(
+ Messages.getString("OptComponentBinding.must.implement")
+ + IValidatable.class);
+ }
+ _bindings = bindings;
+ _property = property;
+ _clazz = clazz;
+ _button = button;
+ _button.addActionListener(this);
+ _enabledByDefault = enabledByDefault;
+ }
+
+ public String getProperty() {
+ return _property;
+ }
+
+ public void clear(IValidatable bean) {
+ _button.setSelected(_enabledByDefault);
+ updateComponents();
+ }
+
+ public void put(IValidatable bean) {
+ try {
+ Object component = PropertyUtils.getProperty(bean, _property);
+ _button.setSelected(component != null);
+ updateComponents();
+ } catch (Exception e) {
+ throw new BindingException(e);
+ }
+ }
+
+ public void get(IValidatable bean) {
+ try {
+ PropertyUtils.setProperty(bean, _property, _button.isSelected()
+ ? _clazz.newInstance() : null);
+ } catch (Exception e) {
+ throw new BindingException(e);
+ }
+ }
+
+ public void markValid() {}
+
+ public void markInvalid() {}
+
+ public void setEnabled(boolean enabled) {} // XXX implement?
+
+ public void actionPerformed(ActionEvent e) {
+ updateComponents();
+ }
+
+ private void updateComponents() {
+ _bindings.setComponentsEnabled(_property, _button.isSelected());
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/OptJTextAreaBinding.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/OptJTextAreaBinding.java
new file mode 100755
index 000000000..3cea776d7
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/OptJTextAreaBinding.java
@@ -0,0 +1,141 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on Sep 3, 2005
+ */
+package net.sf.launch4j.binding;
+
+import java.awt.Color;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.JTextArea;
+import javax.swing.JToggleButton;
+
+import org.apache.commons.beanutils.BeanUtils;
+import org.apache.commons.beanutils.PropertyUtils;
+
+/**
+ * @author Copyright (C) 2005 Grzegorz Kowal
+ */
+public class OptJTextAreaBinding implements Binding, ActionListener {
+ private final String _property;
+ private final String _stateProperty;
+ private final JToggleButton _button;
+ private final JTextArea _textArea;
+ private final Color _validColor;
+
+ public OptJTextAreaBinding(String property, String stateProperty,
+ JToggleButton button, JTextArea textArea) {
+ if (property == null || button == null || textArea == null) {
+ throw new NullPointerException();
+ }
+ if (property.equals("")) {
+ throw new IllegalArgumentException();
+ }
+ _property = property;
+ _stateProperty = stateProperty;
+ _button = button;
+ _textArea = textArea;
+ _validColor = _textArea.getBackground();
+ button.addActionListener(this);
+ }
+
+ public String getProperty() {
+ return _property;
+ }
+
+ public void clear(IValidatable bean) {
+ put(bean);
+ }
+
+ public void put(IValidatable bean) {
+ try {
+ boolean selected = "true".equals(BeanUtils.getProperty(bean,
+ _stateProperty));
+ _button.setSelected(selected);
+ _textArea.setEnabled(selected);
+ List list = (List) PropertyUtils.getProperty(bean, _property);
+ StringBuffer sb = new StringBuffer();
+ if (list != null) {
+ for (int i = 0; i < list.size(); i++) {
+ sb.append(list.get(i));
+ if (i < list.size() - 1) {
+ sb.append("\n");
+ }
+ }
+ }
+ _textArea.setText(sb.toString());
+ } catch (Exception e) {
+ throw new BindingException(e);
+ }
+ }
+
+ public void get(IValidatable bean) {
+ try {
+ String text = _textArea.getText();
+ if (_button.isSelected() && !text.equals("")) {
+ String[] items = text.split("\n");
+ List list = new ArrayList();
+ for (int i = 0; i < items.length; i++) {
+ list.add(items[i]);
+ }
+ PropertyUtils.setProperty(bean, _property, list);
+ } else {
+ PropertyUtils.setProperty(bean, _property, null);
+ }
+ } catch (Exception e) {
+ throw new BindingException(e);
+ }
+ }
+
+ public void markValid() {
+ _textArea.setBackground(_validColor);
+ _textArea.requestFocusInWindow();
+ }
+
+ public void markInvalid() {
+ _textArea.setBackground(Binding.INVALID_COLOR);
+ }
+
+ public void setEnabled(boolean enabled) {
+ _textArea.setEnabled(enabled);
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ _textArea.setEnabled(_button.isSelected());
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/Validator.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/Validator.java
new file mode 100755
index 000000000..88ea67c33
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/Validator.java
@@ -0,0 +1,259 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on 2004-01-30
+ */
+package net.sf.launch4j.binding;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+
+import net.sf.launch4j.Util;
+import net.sf.launch4j.config.ConfigPersister;
+
+/**
+ * @author Copyright (C) 2004 Grzegorz Kowal
+ */
+public class Validator {
+ public static final String ALPHANUMERIC_PATTERN = "[\\w]*?";
+ public static final String ALPHA_PATTERN = "[\\w&&\\D]*?";
+ public static final String NUMERIC_PATTERN = "[\\d]*?";
+ public static final String PATH_PATTERN = "[\\w|[ .,:\\-/\\\\]]*?";
+
+ public static final int MAX_STR = 128;
+ public static final int MAX_PATH = 260;
+ public static final int MAX_BIG_STR = 8192; // or 16384;
+ public static final int MAX_ARGS = 32767 - 2048;
+
+ private Validator() {}
+
+ public static boolean isEmpty(String s) {
+ return s == null || s.equals("");
+ }
+
+ public static void checkNotNull(Object o, String property, String name) {
+ if (o == null) {
+ signalViolation(property,
+ Messages.getString("Validator.empty.field", name));
+ }
+ }
+
+ public static void checkString(String s, int maxLength, String property,
+ String name) {
+ if (s == null || s.length() == 0) {
+ signalViolation(property,
+ Messages.getString("Validator.empty.field", name));
+ }
+ if (s.length() > maxLength) {
+ signalLengthViolation(property, name, maxLength);
+ }
+ }
+
+ public static void checkOptStrings(List strings, int maxLength, int totalMaxLength,
+ String property, String name) {
+ if (strings == null) {
+ return;
+ }
+ int totalLength = 0;
+ for (Iterator iter = strings.iterator(); iter.hasNext();) {
+ String s = (String) iter.next();
+ checkString(s, maxLength, property, name);
+ totalLength += s.length();
+ if (totalLength > totalMaxLength) {
+ signalLengthViolation(property, name, totalMaxLength);
+ }
+ }
+ }
+
+ public static void checkString(String s, int maxLength, String pattern,
+ String property, String name) {
+ checkString(s, maxLength, property, name);
+ if (!s.matches(pattern)) {
+ signalViolation(property,
+ Messages.getString("Validator.invalid.data", name));
+ }
+ }
+
+ public static void checkOptStrings(List strings, int maxLength, int totalMaxLength,
+ String pattern, String property, String name, String msg) {
+ if (strings == null) {
+ return;
+ }
+ int totalLength = 0;
+ for (Iterator iter = strings.iterator(); iter.hasNext();) {
+ String s = (String) iter.next();
+ checkString(s, maxLength, property, name);
+ if (!s.matches(pattern)) {
+ signalViolation(property, msg != null
+ ? msg
+ : Messages.getString("Validator.invalid.data", name));
+ }
+ totalLength += s.length();
+ if (totalLength > totalMaxLength) {
+ signalLengthViolation(property, name, totalMaxLength);
+ }
+ }
+ }
+
+ public static void checkOptString(String s, int maxLength, String property,
+ String name) {
+ if (s == null || s.length() == 0) {
+ return;
+ }
+ if (s.length() > maxLength) {
+ signalLengthViolation(property, name, maxLength);
+ }
+ }
+
+ public static void checkOptString(String s, int maxLength, String pattern,
+ String property, String name) {
+ if (s == null || s.length() == 0) {
+ return;
+ }
+ if (s.length() > maxLength) {
+ signalLengthViolation(property, name, maxLength);
+ }
+ if (!s.matches(pattern)) {
+ signalViolation(property,
+ Messages.getString("Validator.invalid.data", name));
+ }
+ }
+
+ public static void checkRange(int value, int min, int max,
+ String property, String name) {
+ if (value < min || value > max) {
+ signalViolation(property,
+ Messages.getString("Validator.must.be.in.range", name,
+ String.valueOf(min), String.valueOf(max)));
+ }
+ }
+
+ public static void checkRange(char value, char min, char max,
+ String property, String name) {
+ if (value < min || value > max) {
+ signalViolation(property, Messages.getString("Validator.must.be.in.range",
+ name, String.valueOf(min), String.valueOf(max)));
+ }
+ }
+
+ public static void checkMin(int value, int min, String property, String name) {
+ if (value < min) {
+ signalViolation(property,
+ Messages.getString("Validator.must.be.at.least", name,
+ String.valueOf(min)));
+ }
+ }
+
+ public static void checkIn(String s, String[] strings, String property,
+ String name) {
+ if (isEmpty(s)) {
+ signalViolation(property,
+ Messages.getString("Validator.empty.field", name));
+ }
+ List list = Arrays.asList(strings);
+ if (!list.contains(s)) {
+ signalViolation(property,
+ Messages.getString("Validator.invalid.option", name, list.toString()));
+ }
+ }
+
+ public static void checkTrue(boolean condition, String property, String msg) {
+ if (!condition) {
+ signalViolation(property, msg);
+ }
+ }
+
+ public static void checkFalse(boolean condition, String property, String msg) {
+ if (condition) {
+ signalViolation(property, msg);
+ }
+ }
+
+ public static void checkElementsNotNullUnique(Collection c, String property,
+ String msg) {
+ if (c.contains(null)
+ || new HashSet(c).size() != c.size()) {
+ signalViolation(property,
+ Messages.getString("Validator.already.exists", msg));
+ }
+ }
+
+ public static void checkElementsUnique(Collection c, String property, String msg) {
+ if (new HashSet(c).size() != c.size()) {
+ signalViolation(property,
+ Messages.getString("Validator.already.exists", msg));
+ }
+ }
+
+ public static void checkFile(File f, String property, String fileDescription) {
+ File cfgPath = ConfigPersister.getInstance().getConfigPath();
+ if (f == null
+ || f.getPath().equals("")
+ || (!f.exists() && !Util.getAbsoluteFile(cfgPath, f).exists())) {
+ signalViolation(property,
+ Messages.getString("Validator.doesnt.exist", fileDescription));
+ }
+ }
+
+ public static void checkOptFile(File f, String property, String fileDescription) {
+ if (f != null && f.getPath().length() > 0) {
+ checkFile(f, property, fileDescription);
+ }
+ }
+
+ public static void checkRelativeWinPath(String path, String property, String msg) {
+ if (path == null
+ || path.equals("")
+ || path.startsWith("/")
+ || path.startsWith("\\")
+ || path.indexOf(':') != -1) {
+ signalViolation(property, msg);
+ }
+ }
+
+ public static void signalLengthViolation(String property, String name,
+ int maxLength) {
+ signalViolation(property,
+ Messages.getString("Validator.exceeds.max.length", name,
+ String.valueOf(maxLength)));
+ }
+
+ public static void signalViolation(String property, String msg) {
+ throw new InvariantViolationException(property, msg);
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/messages.properties b/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/messages.properties
new file mode 100755
index 000000000..adb5a8886
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/messages.properties
@@ -0,0 +1,52 @@
+#
+# Launch4j (http://launch4j.sourceforge.net/)
+# Cross-platform Java application wrapper for creating Windows native executables.
+#
+# Copyright (c) 2004, 2007 Grzegorz Kowal
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification,
+# are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+# * Neither the name of the Launch4j nor the names of its contributors
+# may be used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+OptComponentBinding.must.implement=Optional component must implement
+
+Validator.empty.field=Enter: {0}
+Validator.invalid.data=Invalid data: {0}
+Validator.must.be.in.range={0} must be in range [{1}-{2}]
+Validator.must.be.at.least={0} must be at least
+Validator.already.exists={0} already exists.
+Validator.doesnt.exist={0} doesn''t exist.
+Validator.exceeds.max.length={0} exceeds the maximum length of {1} characters.
+Validator.invalid.option={0} must be one of [{1}]
+
+Bindings.duplicate.binding=Duplicate binding
+
+JRadioButtonBinding.property.null=Property is null
+JRadioButtonBinding.nothing.selected=Nothing selected
+JRadioButtonBinding.index.out.of.bounds=Button index out of bounds
+
+JComboBoxBinding.property.null=Property is null
+JComboBoxBinding.index.out.of.bounds=Combo box index out of bounds
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/messages_es.properties b/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/messages_es.properties
new file mode 100755
index 000000000..e2e50fcb4
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/binding/messages_es.properties
@@ -0,0 +1,51 @@
+#
+# Launch4j (http://launch4j.sourceforge.net/)
+# Cross-platform Java application wrapper for creating Windows native executables.
+#
+# Copyright (c) 2004, 2007 Grzegorz Kowal, Patricio Martínez Ros
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification,
+# are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+# * Neither the name of the Launch4j nor the names of its contributors
+# may be used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+OptComponentBinding.must.implement=El componente opcional debe ser implementado
+
+Validator.empty.field=Introduzca: {0}
+Validator.invalid.data=Dato no válido: {0}
+Validator.must.be.in.range={0} debe estar en el rango [{1}-{2}]
+Validator.must.be.at.least={0} deb ser al menos
+Validator.already.exists={0} ya existe.
+Validator.doesnt.exist={0} no existe.
+Validator.exceeds.max.length={0} excede la longitud máxima de {1} caracteres.
+Validator.invalid.option={0} must be one of [{1}]
+
+Bindings.duplicate.binding=Binding duplicado
+
+JRadioButtonBinding.property.null=La propiedad es nula
+JRadioButtonBinding.nothing.selected=Nada seleccionado
+JRadioButtonBinding.index.out.of.bounds=Índice de botón fuera de límite
+JComboBoxBinding.property.null=Property is null
+JComboBoxBinding.index.out.of.bounds=Combo box index out of bounds
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/config/ClassPath.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/config/ClassPath.java
new file mode 100755
index 000000000..da7dbd6c4
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/config/ClassPath.java
@@ -0,0 +1,87 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on May 1, 2006
+ */
+package net.sf.launch4j.config;
+
+import java.util.List;
+
+import net.sf.launch4j.binding.IValidatable;
+import net.sf.launch4j.binding.Validator;
+
+/**
+ * @author Copyright (C) 2006 Grzegorz Kowal
+ */
+public class ClassPath implements IValidatable {
+ private String mainClass;
+ private List paths;
+
+ public void checkInvariants() {
+ Validator.checkString(mainClass, Validator.MAX_PATH, "mainClass",
+ Messages.getString("ClassPath.mainClass"));
+ Validator.checkOptStrings(paths,
+ Validator.MAX_PATH,
+ Validator.MAX_BIG_STR,
+ "paths",
+ Messages.getString("ClassPath.path"));
+ }
+
+ public String getMainClass() {
+ return mainClass;
+ }
+
+ public void setMainClass(String mainClass) {
+ this.mainClass = mainClass;
+ }
+
+ public List getPaths() {
+ return paths;
+ }
+
+ public void setPaths(List paths) {
+ this.paths = paths;
+ }
+
+ public String getPathsString() {
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < paths.size(); i++) {
+ sb.append(paths.get(i));
+ if (i < paths.size() - 1) {
+ sb.append(';');
+ }
+ }
+ return sb.toString();
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/config/Config.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/config/Config.java
new file mode 100755
index 000000000..27633bfb4
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/config/Config.java
@@ -0,0 +1,396 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on Apr 21, 2005
+ */
+package net.sf.launch4j.config;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.List;
+
+import net.sf.launch4j.binding.IValidatable;
+import net.sf.launch4j.binding.Validator;
+
+/**
+ * @author Copyright (C) 2005 Grzegorz Kowal
+ */
+public class Config implements IValidatable {
+
+ // 1.x config properties_____________________________________________________________
+ public static final String HEADER = "header";
+ public static final String JAR = "jar";
+ public static final String OUTFILE = "outfile";
+ public static final String ERR_TITLE = "errTitle";
+ public static final String JAR_ARGS = "jarArgs";
+ public static final String CHDIR = "chdir";
+ public static final String CUSTOM_PROC_NAME = "customProcName";
+ public static final String STAY_ALIVE = "stayAlive";
+ public static final String ICON = "icon";
+
+ // __________________________________________________________________________________
+ public static final String DOWNLOAD_URL = "http://java.com/download";
+
+ public static final String GUI_HEADER = "gui";
+ public static final String CONSOLE_HEADER = "console";
+
+ private static final String[] HEADER_TYPES = new String[] { GUI_HEADER,
+ CONSOLE_HEADER };
+
+ private static final String[] PRIORITY_CLASS_NAMES = new String[] { "normal",
+ "idle",
+ "high" };
+
+ private static final int[] PRIORITY_CLASSES = new int[] { 0x00000020,
+ 0x00000040,
+ 0x00000080 };
+
+ private boolean dontWrapJar;
+ private String headerType = GUI_HEADER;
+ private List headerObjects;
+ private List libs;
+ private File jar;
+ private File outfile;
+
+ // Runtime header configuration
+ private String errTitle;
+ private String cmdLine;
+ private String chdir;
+ private String priority;
+ private String downloadUrl;
+ private String supportUrl;
+ private boolean customProcName;
+ private boolean stayAlive;
+ private File manifest;
+ private File icon;
+ private List variables;
+ private SingleInstance singleInstance;
+ private ClassPath classPath;
+ private Jre jre;
+ private Splash splash;
+ private VersionInfo versionInfo;
+ private Msg messages;
+
+ public void checkInvariants() {
+ Validator.checkTrue(outfile != null && outfile.getPath().endsWith(".exe"),
+ "outfile", Messages.getString("Config.specify.output.exe"));
+ if (dontWrapJar) {
+ if (jar != null && !jar.getPath().equals("")) {
+ Validator.checkRelativeWinPath(jar.getPath(), "jar",
+ Messages.getString("Config.application.jar.path"));
+ } else {
+ Validator.checkTrue(classPath != null, "classPath",
+ Messages.getString("ClassPath.or.jar"));
+ }
+ } else {
+ Validator.checkFile(jar, "jar",
+ Messages.getString("Config.application.jar"));
+ }
+ if (!Validator.isEmpty(chdir)) {
+ Validator.checkRelativeWinPath(chdir, "chdir",
+ Messages.getString("Config.chdir.relative"));
+ Validator.checkFalse(chdir.toLowerCase().equals("true")
+ || chdir.toLowerCase().equals("false"),
+ "chdir", Messages.getString("Config.chdir.path"));
+ }
+ Validator.checkOptFile(manifest, "manifest", Messages.getString("Config.manifest"));
+ Validator.checkOptFile(icon, "icon", Messages.getString("Config.icon"));
+ Validator.checkOptString(cmdLine, Validator.MAX_BIG_STR, "jarArgs",
+ Messages.getString("Config.jar.arguments"));
+ Validator.checkOptString(errTitle, Validator.MAX_STR, "errTitle",
+ Messages.getString("Config.error.title"));
+ Validator.checkOptString(downloadUrl, 256,
+ "downloadUrl", Messages.getString("Config.download.url"));
+ Validator.checkOptString(supportUrl, 256,
+ "supportUrl", Messages.getString("Config.support.url"));
+ Validator.checkIn(getHeaderType(), HEADER_TYPES, "headerType",
+ Messages.getString("Config.header.type"));
+ Validator.checkFalse(getHeaderType().equals(CONSOLE_HEADER) && splash != null,
+ "headerType",
+ Messages.getString("Config.splash.not.impl.by.console.hdr"));
+ Validator.checkOptStrings(variables,
+ Validator.MAX_ARGS,
+ Validator.MAX_ARGS,
+ "[^=%\t]+=[^=\t]+",
+ "variables",
+ Messages.getString("Config.variables"),
+ Messages.getString("Config.variables.err"));
+ Validator.checkIn(getPriority(), PRIORITY_CLASS_NAMES, "priority",
+ Messages.getString("Config.priority"));
+ jre.checkInvariants();
+ }
+
+ public void validate() {
+ checkInvariants();
+ if (classPath != null) {
+ classPath.checkInvariants();
+ }
+ if (splash != null) {
+ splash.checkInvariants();
+ }
+ if (versionInfo != null) {
+ versionInfo.checkInvariants();
+ }
+ }
+
+ /** Change current directory to EXE location. */
+ public String getChdir() {
+ return chdir;
+ }
+
+ public void setChdir(String chdir) {
+ this.chdir = chdir;
+ }
+
+ /** Constant command line arguments passed to the application. */
+ public String getCmdLine() {
+ return cmdLine;
+ }
+
+ public void setCmdLine(String cmdLine) {
+ this.cmdLine = cmdLine;
+ }
+
+ /** Optional, error message box title. */
+ public String getErrTitle() {
+ return errTitle;
+ }
+
+ public void setErrTitle(String errTitle) {
+ this.errTitle = errTitle;
+ }
+
+ /** launch4j header file. */
+ public String getHeaderType() {
+ return headerType.toLowerCase();
+ }
+
+ public void setHeaderType(String headerType) {
+ this.headerType = headerType;
+ }
+
+ /** launch4j header file index - used by GUI. */
+ public int getHeaderTypeIndex() {
+ int x = Arrays.asList(HEADER_TYPES).indexOf(getHeaderType());
+ return x != -1 ? x : 0;
+ }
+
+ public void setHeaderTypeIndex(int headerTypeIndex) {
+ headerType = HEADER_TYPES[headerTypeIndex];
+ }
+
+ public boolean isCustomHeaderObjects() {
+ return headerObjects != null && !headerObjects.isEmpty();
+ }
+
+ public List getHeaderObjects() {
+ return isCustomHeaderObjects() ? headerObjects
+ : getHeaderType().equals(GUI_HEADER)
+ ? LdDefaults.GUI_HEADER_OBJECTS
+ : LdDefaults.CONSOLE_HEADER_OBJECTS;
+ }
+
+ public void setHeaderObjects(List headerObjects) {
+ this.headerObjects = headerObjects;
+ }
+
+ public boolean isCustomLibs() {
+ return libs != null && !libs.isEmpty();
+ }
+
+ public List getLibs() {
+ return isCustomLibs() ? libs : LdDefaults.LIBS;
+ }
+
+ public void setLibs(List libs) {
+ this.libs = libs;
+ }
+
+ /** Wrapper's manifest for User Account Control. */
+ public File getManifest() {
+ return manifest;
+ }
+
+ public void setManifest(File manifest) {
+ this.manifest = manifest;
+ }
+
+ /** ICO file. */
+ public File getIcon() {
+ return icon;
+ }
+
+ public void setIcon(File icon) {
+ this.icon = icon;
+ }
+
+ /** Jar to wrap. */
+ public File getJar() {
+ return jar;
+ }
+
+ public void setJar(File jar) {
+ this.jar = jar;
+ }
+
+ public List getVariables() {
+ return variables;
+ }
+
+ public void setVariables(List variables) {
+ this.variables = variables;
+ }
+
+ public ClassPath getClassPath() {
+ return classPath;
+ }
+
+ public void setClassPath(ClassPath classpath) {
+ this.classPath = classpath;
+ }
+
+ /** JRE configuration */
+ public Jre getJre() {
+ return jre;
+ }
+
+ public void setJre(Jre jre) {
+ this.jre = jre;
+ }
+
+ /** Output EXE file. */
+ public File getOutfile() {
+ return outfile;
+ }
+
+ public void setOutfile(File outfile) {
+ this.outfile = outfile;
+ }
+
+ /** Custom process name as the output EXE file name. */
+ public boolean isCustomProcName() {
+ return customProcName;
+ }
+
+ public void setCustomProcName(boolean customProcName) {
+ this.customProcName = customProcName;
+ }
+
+ /** Splash screen configuration. */
+ public Splash getSplash() {
+ return splash;
+ }
+
+ public void setSplash(Splash splash) {
+ this.splash = splash;
+ }
+
+ /** Stay alive after launching the application. */
+ public boolean isStayAlive() {
+ return stayAlive;
+ }
+
+ public void setStayAlive(boolean stayAlive) {
+ this.stayAlive = stayAlive;
+ }
+
+ public VersionInfo getVersionInfo() {
+ return versionInfo;
+ }
+
+ public void setVersionInfo(VersionInfo versionInfo) {
+ this.versionInfo = versionInfo;
+ }
+
+ public boolean isDontWrapJar() {
+ return dontWrapJar;
+ }
+
+ public void setDontWrapJar(boolean dontWrapJar) {
+ this.dontWrapJar = dontWrapJar;
+ }
+
+ public int getPriorityIndex() {
+ int x = Arrays.asList(PRIORITY_CLASS_NAMES).indexOf(getPriority());
+ return x != -1 ? x : 0;
+ }
+
+ public void setPriorityIndex(int x) {
+ priority = PRIORITY_CLASS_NAMES[x];
+ }
+
+ public String getPriority() {
+ return Validator.isEmpty(priority) ? PRIORITY_CLASS_NAMES[0] : priority;
+ }
+
+ public void setPriority(String priority) {
+ this.priority = priority;
+ }
+
+ public int getPriorityClass() {
+ return PRIORITY_CLASSES[getPriorityIndex()];
+ }
+
+ public String getDownloadUrl() {
+ return downloadUrl == null ? DOWNLOAD_URL : downloadUrl;
+ }
+
+ public void setDownloadUrl(String downloadUrl) {
+ this.downloadUrl = downloadUrl;
+ }
+
+ public String getSupportUrl() {
+ return supportUrl;
+ }
+
+ public void setSupportUrl(String supportUrl) {
+ this.supportUrl = supportUrl;
+ }
+
+ public Msg getMessages() {
+ return messages;
+ }
+
+ public void setMessages(Msg messages) {
+ this.messages = messages;
+ }
+
+ public SingleInstance getSingleInstance() {
+ return singleInstance;
+ }
+
+ public void setSingleInstance(SingleInstance singleInstance) {
+ this.singleInstance = singleInstance;
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/config/ConfigPersister.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/config/ConfigPersister.java
new file mode 100755
index 000000000..43daf8681
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/config/ConfigPersister.java
@@ -0,0 +1,249 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on Apr 22, 2005
+ */
+package net.sf.launch4j.config;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import net.sf.launch4j.Util;
+
+import com.thoughtworks.xstream.XStream;
+import com.thoughtworks.xstream.io.xml.DomDriver;
+
+/**
+ * @author Copyright (C) 2005 Grzegorz Kowal
+ */
+public class ConfigPersister {
+
+ private static final ConfigPersister _instance = new ConfigPersister();
+
+ private final XStream _xstream;
+ private Config _config;
+ private File _configPath;
+
+ private ConfigPersister() {
+ _xstream = new XStream(new DomDriver());
+ _xstream.alias("launch4jConfig", Config.class);
+ _xstream.alias("classPath", ClassPath.class);
+ _xstream.alias("jre", Jre.class);
+ _xstream.alias("splash", Splash.class);
+ _xstream.alias("versionInfo", VersionInfo.class);
+
+ _xstream.addImplicitCollection(Config.class, "headerObjects", "obj",
+ String.class);
+ _xstream.addImplicitCollection(Config.class, "libs", "lib", String.class);
+ _xstream.addImplicitCollection(Config.class, "variables", "var", String.class);
+ _xstream.addImplicitCollection(ClassPath.class, "paths", "cp", String.class);
+ _xstream.addImplicitCollection(Jre.class, "options", "opt", String.class);
+ }
+
+ public static ConfigPersister getInstance() {
+ return _instance;
+ }
+
+ public Config getConfig() {
+ return _config;
+ }
+
+ public File getConfigPath() {
+ return _configPath;
+ }
+
+ public File getOutputPath() throws IOException {
+ if (_config.getOutfile().isAbsolute()) {
+ return _config.getOutfile().getParentFile();
+ }
+ File parent = _config.getOutfile().getParentFile();
+ return (parent != null) ? new File(_configPath, parent.getPath()) : _configPath;
+ }
+
+ public File getOutputFile() throws IOException {
+ return _config.getOutfile().isAbsolute()
+ ? _config.getOutfile()
+ : new File(getOutputPath(), _config.getOutfile().getName());
+ }
+
+ public void createBlank() {
+ _config = new Config();
+ _config.setJre(new Jre());
+ _configPath = null;
+ }
+
+ public void setAntConfig(Config c, File basedir) {
+ _config = c;
+ _configPath = basedir;
+ }
+
+ public void load(File f) throws ConfigPersisterException {
+ try {
+ FileReader r = new FileReader(f);
+ char[] buf = new char[(int) f.length()];
+ r.read(buf);
+ r.close();
+ // Convert 2.x config to 3.x
+ String s = String.valueOf(buf)
+ .replaceAll("0<", "gui<")
+ .replaceAll("1<", "console<")
+ .replaceAll("jarArgs>", "cmdLine>")
+ .replaceAll("", "")
+ .replaceAll("args>", "opt>")
+ .replaceAll("", "")
+ .replaceAll("false",
+ "" + Jre.JDK_PREFERENCE_PREFER_JRE + "")
+ .replaceAll("true",
+ "" + Jre.JDK_PREFERENCE_JRE_ONLY + "")
+ .replaceAll("0", "")
+ .replaceAll("0", "");
+ _config = (Config) _xstream.fromXML(s);
+ setConfigPath(f);
+ } catch (Exception e) {
+ throw new ConfigPersisterException(e);
+ }
+ }
+
+ /**
+ * Imports launch4j 1.x.x config file.
+ */
+ public void loadVersion1(File f) throws ConfigPersisterException {
+ try {
+ Props props = new Props(f);
+ _config = new Config();
+ String header = props.getProperty(Config.HEADER);
+ _config.setHeaderType(header == null
+ || header.toLowerCase().equals("guihead.bin") ? Config.GUI_HEADER
+ : Config.CONSOLE_HEADER);
+ _config.setJar(props.getFile(Config.JAR));
+ _config.setOutfile(props.getFile(Config.OUTFILE));
+ _config.setJre(new Jre());
+ _config.getJre().setPath(props.getProperty(Jre.PATH));
+ _config.getJre().setMinVersion(props.getProperty(Jre.MIN_VERSION));
+ _config.getJre().setMaxVersion(props.getProperty(Jre.MAX_VERSION));
+ String args = props.getProperty(Jre.ARGS);
+ if (args != null) {
+ List jreOptions = new ArrayList();
+ jreOptions.add(args);
+ _config.getJre().setOptions(jreOptions);
+ }
+ _config.setCmdLine(props.getProperty(Config.JAR_ARGS));
+ _config.setChdir("true".equals(props.getProperty(Config.CHDIR))
+ ? "." : null);
+ _config.setCustomProcName("true".equals(
+ props.getProperty("setProcName"))); // 1.x
+ _config.setStayAlive("true".equals(props.getProperty(Config.STAY_ALIVE)));
+ _config.setErrTitle(props.getProperty(Config.ERR_TITLE));
+ _config.setIcon(props.getFile(Config.ICON));
+ File splashFile = props.getFile(Splash.SPLASH_FILE);
+ if (splashFile != null) {
+ _config.setSplash(new Splash());
+ _config.getSplash().setFile(splashFile);
+ String waitfor = props.getProperty("waitfor"); // 1.x
+ _config.getSplash().setWaitForWindow(waitfor != null
+ && !waitfor.equals(""));
+ String splashTimeout = props.getProperty(Splash.TIMEOUT);
+ if (splashTimeout != null) {
+ _config.getSplash().setTimeout(Integer.parseInt(splashTimeout));
+ }
+ _config.getSplash().setTimeoutErr("true".equals(
+ props.getProperty(Splash.TIMEOUT_ERR)));
+ } else {
+ _config.setSplash(null);
+ }
+ setConfigPath(f);
+ } catch (IOException e) {
+ throw new ConfigPersisterException(e);
+ }
+ }
+
+ public void save(File f) throws ConfigPersisterException {
+ try {
+ BufferedWriter w = new BufferedWriter(new FileWriter(f));
+ _xstream.toXML(_config, w);
+ w.close();
+ setConfigPath(f);
+ } catch (Exception e) {
+ throw new ConfigPersisterException(e);
+ }
+ }
+
+ private void setConfigPath(File configFile) {
+ _configPath = configFile.getAbsoluteFile().getParentFile();
+ }
+
+ private class Props {
+ final Properties _properties = new Properties();
+
+ public Props(File f) throws IOException {
+ FileInputStream is = null;
+ try {
+ is = new FileInputStream(f);
+ _properties.load(is);
+ } finally {
+ Util.close(is);
+ }
+ }
+
+ /**
+ * Get property and remove trailing # comments.
+ */
+ public String getProperty(String key) {
+ String p = _properties.getProperty(key);
+ if (p == null) {
+ return null;
+ }
+ int x = p.indexOf('#');
+ if (x == -1) {
+ return p;
+ }
+ do {
+ x--;
+ } while (x > 0 && (p.charAt(x) == ' ' || p.charAt(x) == '\t'));
+ return (x == 0) ? "" : p.substring(0, x + 1);
+ }
+
+ public File getFile(String key) {
+ String value = getProperty(key);
+ return value != null ? new File(value) : null;
+ }
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/config/ConfigPersisterException.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/config/ConfigPersisterException.java
new file mode 100755
index 000000000..29940b945
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/config/ConfigPersisterException.java
@@ -0,0 +1,51 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on Apr 22, 2005
+ */
+package net.sf.launch4j.config;
+
+/**
+ * @author Copyright (C) 2005 Grzegorz Kowal
+ */
+public class ConfigPersisterException extends Exception {
+
+ public ConfigPersisterException(String msg, Throwable t) {
+ super(msg, t);
+ }
+
+ public ConfigPersisterException(Throwable t) {
+ super(t);
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/config/Jre.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/config/Jre.java
new file mode 100755
index 000000000..0df45bb84
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/config/Jre.java
@@ -0,0 +1,235 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on Apr 21, 2005
+ */
+package net.sf.launch4j.config;
+
+import java.util.Arrays;
+import java.util.List;
+
+import net.sf.launch4j.binding.IValidatable;
+import net.sf.launch4j.binding.Validator;
+
+/**
+ * @author Copyright (C) 2005 Grzegorz Kowal
+ */
+public class Jre implements IValidatable {
+
+ // 1.x config properties_____________________________________________________________
+ public static final String PATH = "jrepath";
+ public static final String MIN_VERSION = "javamin";
+ public static final String MAX_VERSION = "javamax";
+ public static final String ARGS = "jvmArgs";
+
+ // __________________________________________________________________________________
+ public static final String VERSION_PATTERN = "(\\d\\.){2}\\d(_\\d+)?";
+
+ public static final String JDK_PREFERENCE_JRE_ONLY = "jreOnly";
+ public static final String JDK_PREFERENCE_PREFER_JRE = "preferJre";
+ public static final String JDK_PREFERENCE_PREFER_JDK = "preferJdk";
+ public static final String JDK_PREFERENCE_JDK_ONLY = "jdkOnly";
+
+ private static final String[] JDK_PREFERENCE_NAMES = new String[] {
+ JDK_PREFERENCE_JRE_ONLY,
+ JDK_PREFERENCE_PREFER_JRE,
+ JDK_PREFERENCE_PREFER_JDK,
+ JDK_PREFERENCE_JDK_ONLY };
+
+ public static final int DEFAULT_JDK_PREFERENCE_INDEX
+ = Arrays.asList(JDK_PREFERENCE_NAMES).indexOf(JDK_PREFERENCE_PREFER_JRE);
+
+ private String path;
+ private String minVersion;
+ private String maxVersion;
+ private String jdkPreference;
+ private Integer initialHeapSize;
+ private Integer initialHeapPercent;
+ private Integer maxHeapSize;
+ private Integer maxHeapPercent;
+ private List options;
+
+ public void checkInvariants() {
+ Validator.checkOptString(minVersion, 10, VERSION_PATTERN,
+ "jre.minVersion", Messages.getString("Jre.min.version"));
+ Validator.checkOptString(maxVersion, 10, VERSION_PATTERN,
+ "jre.maxVersion", Messages.getString("Jre.max.version"));
+ if (Validator.isEmpty(path)) {
+ Validator.checkFalse(Validator.isEmpty(minVersion),
+ "jre.minVersion", Messages.getString("Jre.specify.jre.min.version.or.path"));
+ } else {
+ Validator.checkString(path, Validator.MAX_PATH,
+ "jre.path", Messages.getString("Jre.bundled.path"));
+ }
+ if (!Validator.isEmpty(maxVersion)) {
+ Validator.checkFalse(Validator.isEmpty(minVersion),
+ "jre.minVersion", Messages.getString("Jre.specify.min.version"));
+ Validator.checkTrue(minVersion.compareTo(maxVersion) < 0,
+ "jre.maxVersion", Messages.getString("Jre.max.greater.than.min"));
+ }
+ Validator.checkTrue(initialHeapSize == null || maxHeapSize != null,
+ "jre.maxHeapSize", Messages.getString("Jre.initial.and.max.heap"));
+ Validator.checkTrue(initialHeapSize == null || initialHeapSize.intValue() > 0,
+ "jre.initialHeapSize", Messages.getString("Jre.initial.heap"));
+ Validator.checkTrue(maxHeapSize == null || (maxHeapSize.intValue()
+ >= ((initialHeapSize != null) ? initialHeapSize.intValue() : 1)),
+ "jre.maxHeapSize", Messages.getString("Jre.max.heap"));
+ Validator.checkTrue(initialHeapPercent == null || maxHeapPercent != null,
+ "jre.maxHeapPercent", Messages.getString("Jre.initial.and.max.heap"));
+ if (initialHeapPercent != null) {
+ Validator.checkRange(initialHeapPercent.intValue(), 1, 100,
+ "jre.initialHeapPercent",
+ Messages.getString("Jre.initial.heap.percent"));
+ }
+ if (maxHeapPercent != null) {
+ Validator.checkRange(maxHeapPercent.intValue(),
+ initialHeapPercent != null ? initialHeapPercent.intValue() : 1, 100,
+ "jre.maxHeapPercent",
+ Messages.getString("Jre.max.heap.percent"));
+ }
+ Validator.checkIn(getJdkPreference(), JDK_PREFERENCE_NAMES,
+ "jre.jdkPreference", Messages.getString("Jre.jdkPreference.invalid"));
+ Validator.checkOptStrings(options,
+ Validator.MAX_ARGS,
+ Validator.MAX_ARGS,
+ "[^\"]*|([^\"]*\"[^\"]*\"[^\"]*)*",
+ "jre.options",
+ Messages.getString("Jre.jvm.options"),
+ Messages.getString("Jre.jvm.options.unclosed.quotation"));
+
+ // Quoted variable references: "[^%]*|([^%]*\"([^%]*%[^%]+%[^%]*)+\"[^%]*)*"
+ Validator.checkOptStrings(options,
+ Validator.MAX_ARGS,
+ Validator.MAX_ARGS,
+ "[^%]*|([^%]*([^%]*%[^%]+%[^%]*)+[^%]*)*",
+ "jre.options",
+ Messages.getString("Jre.jvm.options"),
+ Messages.getString("Jre.jvm.options.variable"));
+ }
+
+ /** JVM options */
+ public List getOptions() {
+ return options;
+ }
+
+ public void setOptions(List options) {
+ this.options = options;
+ }
+
+ /** Max Java version (x.x.x) */
+ public String getMaxVersion() {
+ return maxVersion;
+ }
+
+ public void setMaxVersion(String maxVersion) {
+ this.maxVersion = maxVersion;
+ }
+
+ /** Min Java version (x.x.x) */
+ public String getMinVersion() {
+ return minVersion;
+ }
+
+ public void setMinVersion(String minVersion) {
+ this.minVersion = minVersion;
+ }
+
+ /** Preference for standalone JRE or JDK-private JRE */
+ public String getJdkPreference() {
+ return Validator.isEmpty(jdkPreference) ? JDK_PREFERENCE_PREFER_JRE
+ : jdkPreference;
+ }
+
+ public void setJdkPreference(String jdkPreference) {
+ this.jdkPreference = jdkPreference;
+ }
+
+ /** Preference for standalone JRE or JDK-private JRE */
+ public int getJdkPreferenceIndex() {
+ int x = Arrays.asList(JDK_PREFERENCE_NAMES).indexOf(getJdkPreference());
+ return x != -1 ? x : DEFAULT_JDK_PREFERENCE_INDEX;
+ }
+
+ public void setJdkPreferenceIndex(int x) {
+ jdkPreference = JDK_PREFERENCE_NAMES[x];
+ }
+
+ /** JRE path */
+ public String getPath() {
+ return path;
+ }
+
+ public void setPath(String path) {
+ this.path = path;
+ }
+
+ /** Initial heap size in MB */
+ public Integer getInitialHeapSize() {
+ return initialHeapSize;
+ }
+
+ public void setInitialHeapSize(Integer initialHeapSize) {
+ this.initialHeapSize = getInteger(initialHeapSize);
+ }
+
+ /** Max heap size in MB */
+ public Integer getMaxHeapSize() {
+ return maxHeapSize;
+ }
+
+ public void setMaxHeapSize(Integer maxHeapSize) {
+ this.maxHeapSize = getInteger(maxHeapSize);
+ }
+
+ public Integer getInitialHeapPercent() {
+ return initialHeapPercent;
+ }
+
+ public void setInitialHeapPercent(Integer initialHeapPercent) {
+ this.initialHeapPercent = getInteger(initialHeapPercent);
+ }
+
+ public Integer getMaxHeapPercent() {
+ return maxHeapPercent;
+ }
+
+ public void setMaxHeapPercent(Integer maxHeapPercent) {
+ this.maxHeapPercent = getInteger(maxHeapPercent);
+ }
+
+ /** Convert 0 to null */
+ private Integer getInteger(Integer i) {
+ return i != null && i.intValue() == 0 ? null : i;
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/config/LdDefaults.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/config/LdDefaults.java
new file mode 100755
index 000000000..55f457cc3
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/config/LdDefaults.java
@@ -0,0 +1,62 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on Sep 3, 2005
+ */
+package net.sf.launch4j.config;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class LdDefaults {
+
+ public static final List GUI_HEADER_OBJECTS = Arrays.asList(new String[] {
+ "w32api/crt2.o",
+ "head/guihead.o",
+ "head/head.o" });
+
+ public static final List CONSOLE_HEADER_OBJECTS = Arrays.asList(new String[] {
+ "w32api/crt2.o",
+ "head/consolehead.o",
+ "head/head.o"});
+
+ public static final List LIBS = Arrays.asList(new String[] {
+ "w32api/libmingw32.a",
+ "w32api/libgcc.a",
+ "w32api/libmsvcrt.a",
+ "w32api/libkernel32.a",
+ "w32api/libuser32.a",
+ "w32api/libadvapi32.a",
+ "w32api/libshell32.a" });
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/config/Messages.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/config/Messages.java
new file mode 100755
index 000000000..a3f344e59
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/config/Messages.java
@@ -0,0 +1,78 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package net.sf.launch4j.config;
+
+import java.text.MessageFormat;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+public class Messages {
+ private static final String BUNDLE_NAME = "net.sf.launch4j.config.messages";
+
+ private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle
+ .getBundle(BUNDLE_NAME);
+ private static final MessageFormat FORMATTER = new MessageFormat("");
+
+ private Messages() {
+ }
+
+ public static String getString(String key) {
+ try {
+ return RESOURCE_BUNDLE.getString(key);
+ } catch (MissingResourceException e) {
+ return '!' + key + '!';
+ }
+ }
+
+ public static String getString(String key, String arg0) {
+ return getString(key, new Object[] {arg0});
+ }
+
+ public static String getString(String key, String arg0, String arg1) {
+ return getString(key, new Object[] {arg0, arg1});
+ }
+
+ public static String getString(String key, String arg0, String arg1, String arg2) {
+ return getString(key, new Object[] {arg0, arg1, arg2});
+ }
+
+ public static String getString(String key, Object[] args) {
+ try {
+ FORMATTER.applyPattern(RESOURCE_BUNDLE.getString(key));
+ return FORMATTER.format(args);
+ } catch (MissingResourceException e) {
+ return '!' + key + '!';
+ }
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/config/Msg.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/config/Msg.java
new file mode 100755
index 000000000..ea3acfa34
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/config/Msg.java
@@ -0,0 +1,111 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on Oct 8, 2006
+ */
+package net.sf.launch4j.config;
+
+import net.sf.launch4j.binding.IValidatable;
+import net.sf.launch4j.binding.Validator;
+
+/**
+ * @author Copyright (C) 2006 Grzegorz Kowal
+ */
+public class Msg implements IValidatable {
+ private String startupErr;
+ private String bundledJreErr;
+ private String jreVersionErr;
+ private String launcherErr;
+ private String instanceAlreadyExistsMsg;
+
+ public void checkInvariants() {
+ Validator.checkOptString(startupErr, 1024, "startupErr",
+ Messages.getString("Msg.startupErr"));
+ Validator.checkOptString(bundledJreErr, 1024, "bundledJreErr",
+ Messages.getString("Msg.bundledJreErr"));
+ Validator.checkOptString(jreVersionErr, 1024, "jreVersionErr",
+ Messages.getString("Msg.jreVersionErr"));
+ Validator.checkOptString(launcherErr, 1024, "launcherErr",
+ Messages.getString("Msg.launcherErr"));
+ Validator.checkOptString(instanceAlreadyExistsMsg, 1024, "instanceAlreadyExistsMsg",
+ Messages.getString("Msg.instanceAlreadyExistsMsg"));
+ }
+
+ public String getStartupErr() {
+ return !Validator.isEmpty(startupErr) ? startupErr
+ : "An error occurred while starting the application.";
+ }
+
+ public void setStartupErr(String startupErr) {
+ this.startupErr = startupErr;
+ }
+
+ public String getBundledJreErr() {
+ return !Validator.isEmpty(bundledJreErr) ? bundledJreErr
+ : "This application was configured to use a bundled Java Runtime" +
+ " Environment but the runtime is missing or corrupted.";
+ }
+
+ public void setBundledJreErr(String bundledJreErr) {
+ this.bundledJreErr = bundledJreErr;
+ }
+
+ public String getJreVersionErr() {
+ return !Validator.isEmpty(jreVersionErr) ? jreVersionErr
+ : "This application requires a Java Runtime Environment";
+ }
+
+ public void setJreVersionErr(String jreVersionErr) {
+ this.jreVersionErr = jreVersionErr;
+ }
+
+ public String getLauncherErr() {
+ return !Validator.isEmpty(launcherErr) ? launcherErr
+ : "The registry refers to a nonexistent Java Runtime Environment" +
+ " installation or the runtime is corrupted.";
+ }
+
+ public void setLauncherErr(String launcherErr) {
+ this.launcherErr = launcherErr;
+ }
+
+ public String getInstanceAlreadyExistsMsg() {
+ return !Validator.isEmpty(instanceAlreadyExistsMsg) ? instanceAlreadyExistsMsg
+ : "An application instance is already running.";
+ }
+
+ public void setInstanceAlreadyExistsMsg(String instanceAlreadyExistsMsg) {
+ this.instanceAlreadyExistsMsg = instanceAlreadyExistsMsg;
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/config/SingleInstance.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/config/SingleInstance.java
new file mode 100755
index 000000000..0ae340cd7
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/config/SingleInstance.java
@@ -0,0 +1,74 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/**
+ * Created on 2007-09-16
+ */
+package net.sf.launch4j.config;
+
+import net.sf.launch4j.binding.IValidatable;
+import net.sf.launch4j.binding.Validator;
+
+/**
+ * @author Copyright (C) 2007 Grzegorz Kowal
+ */
+public class SingleInstance implements IValidatable {
+
+ private String mutexName;
+ private String windowTitle;
+
+ public void checkInvariants() {
+ Validator.checkString(mutexName, Validator.MAX_STR,
+ "singleInstance.mutexName",
+ Messages.getString("SingleInstance.mutexName"));
+ Validator.checkOptString(windowTitle, Validator.MAX_STR,
+ "singleInstance.windowTitle",
+ Messages.getString("SingleInstance.windowTitle"));
+ }
+
+ public String getWindowTitle() {
+ return windowTitle;
+ }
+
+ public void setWindowTitle(String appWindowName) {
+ this.windowTitle = appWindowName;
+ }
+
+ public String getMutexName() {
+ return mutexName;
+ }
+
+ public void setMutexName(String mutexName) {
+ this.mutexName = mutexName;
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/config/Splash.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/config/Splash.java
new file mode 100755
index 000000000..f736f8208
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/config/Splash.java
@@ -0,0 +1,103 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on Apr 21, 2005
+ */
+package net.sf.launch4j.config;
+
+import java.io.File;
+
+import net.sf.launch4j.binding.IValidatable;
+import net.sf.launch4j.binding.Validator;
+
+/**
+ * @author Copyright (C) 2005 Grzegorz Kowal
+ */
+public class Splash implements IValidatable {
+
+ // 1.x config properties_____________________________________________________________
+ public static final String SPLASH_FILE = "splash";
+ public static final String WAIT_FOR_TITLE = "waitForTitle";
+ public static final String TIMEOUT = "splashTimeout";
+ public static final String TIMEOUT_ERR = "splashTimeoutErr";
+
+ // __________________________________________________________________________________
+ private File file;
+ private boolean waitForWindow = true;
+ private int timeout = 60;
+ private boolean timeoutErr = true;
+
+ public void checkInvariants() {
+ Validator.checkFile(file, "splash.file",
+ Messages.getString("Splash.splash.file"));
+ Validator.checkRange(timeout, 1, 60 * 15, "splash.timeout",
+ Messages.getString("Splash.splash.timeout"));
+ }
+
+ /** Splash screen in BMP format. */
+ public File getFile() {
+ return file;
+ }
+
+ public void setFile(File file) {
+ this.file = file;
+ }
+
+ /** Splash timeout in seconds. */
+ public int getTimeout() {
+ return timeout;
+ }
+
+ public void setTimeout(int timeout) {
+ this.timeout = timeout;
+ }
+
+ /** Signal error on splash timeout. */
+ public boolean isTimeoutErr() {
+ return timeoutErr;
+ }
+
+ public void setTimeoutErr(boolean timeoutErr) {
+ this.timeoutErr = timeoutErr;
+ }
+
+ /** Hide splash screen when the child process displayes the first window. */
+ public boolean getWaitForWindow() {
+ return waitForWindow;
+ }
+
+ public void setWaitForWindow(boolean waitForWindow) {
+ this.waitForWindow = waitForWindow;
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/config/VersionInfo.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/config/VersionInfo.java
new file mode 100755
index 000000000..d719460c2
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/config/VersionInfo.java
@@ -0,0 +1,168 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on May 21, 2005
+ */
+package net.sf.launch4j.config;
+
+import net.sf.launch4j.binding.IValidatable;
+import net.sf.launch4j.binding.Validator;
+
+/**
+ * @author Copyright (C) 2005 Grzegorz Kowal
+ */
+public class VersionInfo implements IValidatable {
+ public static final String VERSION_PATTERN = "(\\d+\\.){3}\\d+";
+
+ private String fileVersion;
+ private String txtFileVersion;
+ private String fileDescription;
+ private String copyright;
+ private String productVersion;
+ private String txtProductVersion;
+ private String productName;
+ private String companyName;
+ private String internalName;
+ private String originalFilename;
+
+ public void checkInvariants() {
+ Validator.checkString(fileVersion, 20, VERSION_PATTERN,
+ "versionInfo.fileVersion",
+ Messages.getString("VersionInfo.file.version"));
+ Validator.checkString(txtFileVersion, 50, "versionInfo.txtFileVersion",
+ Messages.getString("VersionInfo.txt.file.version"));
+ Validator.checkString(fileDescription, 150, "versionInfo.fileDescription",
+ Messages.getString("VersionInfo.file.description"));
+ Validator.checkString(copyright, 150, "versionInfo.copyright",
+ Messages.getString("VersionInfo.copyright"));
+ Validator.checkString(productVersion, 20, VERSION_PATTERN,
+ "versionInfo.productVersion",
+ Messages.getString("VersionInfo.product.version"));
+ Validator.checkString(txtProductVersion, 50, "versionInfo.txtProductVersion",
+ Messages.getString("VersionInfo.txt.product.version"));
+ Validator.checkString(productName, 150, "versionInfo.productName",
+ Messages.getString("VersionInfo.product.name"));
+ Validator.checkOptString(companyName, 150, "versionInfo.companyName",
+ Messages.getString("VersionInfo.company.name"));
+ Validator.checkString(internalName, 50, "versionInfo.internalName",
+ Messages.getString("VersionInfo.internal.name"));
+ Validator.checkTrue(!internalName.endsWith(".exe"), "versionInfo.internalName",
+ Messages.getString("VersionInfo.internal.name.not.exe"));
+ Validator.checkString(originalFilename, 50, "versionInfo.originalFilename",
+ Messages.getString("VersionInfo.original.filename"));
+ Validator.checkTrue(originalFilename.endsWith(".exe"),
+ "versionInfo.originalFilename",
+ Messages.getString("VersionInfo.original.filename.exe"));
+ }
+
+ public String getCompanyName() {
+ return companyName;
+ }
+
+ public void setCompanyName(String companyName) {
+ this.companyName = companyName;
+ }
+
+ public String getCopyright() {
+ return copyright;
+ }
+
+ public void setCopyright(String copyright) {
+ this.copyright = copyright;
+ }
+
+ public String getFileDescription() {
+ return fileDescription;
+ }
+
+ public void setFileDescription(String fileDescription) {
+ this.fileDescription = fileDescription;
+ }
+
+ public String getFileVersion() {
+ return fileVersion;
+ }
+
+ public void setFileVersion(String fileVersion) {
+ this.fileVersion = fileVersion;
+ }
+
+ public String getInternalName() {
+ return internalName;
+ }
+
+ public void setInternalName(String internalName) {
+ this.internalName = internalName;
+ }
+
+ public String getOriginalFilename() {
+ return originalFilename;
+ }
+
+ public void setOriginalFilename(String originalFilename) {
+ this.originalFilename = originalFilename;
+ }
+
+ public String getProductName() {
+ return productName;
+ }
+
+ public void setProductName(String productName) {
+ this.productName = productName;
+ }
+
+ public String getProductVersion() {
+ return productVersion;
+ }
+
+ public void setProductVersion(String productVersion) {
+ this.productVersion = productVersion;
+ }
+
+ public String getTxtFileVersion() {
+ return txtFileVersion;
+ }
+
+ public void setTxtFileVersion(String txtFileVersion) {
+ this.txtFileVersion = txtFileVersion;
+ }
+
+ public String getTxtProductVersion() {
+ return txtProductVersion;
+ }
+
+ public void setTxtProductVersion(String txtProductVersion) {
+ this.txtProductVersion = txtProductVersion;
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/config/messages.properties b/build/windows/launcher/launch4j/src/net/sf/launch4j/config/messages.properties
new file mode 100755
index 000000000..5753663f4
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/config/messages.properties
@@ -0,0 +1,93 @@
+#
+# Launch4j (http://launch4j.sourceforge.net/)
+# Cross-platform Java application wrapper for creating Windows native executables.
+#
+# Copyright (c) 2004, 2007 Grzegorz Kowal
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification,
+# are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+# * Neither the name of the Launch4j nor the names of its contributors
+# may be used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+Splash.splash.file=Splash file
+Splash.splash.timeout=Splash timeout
+
+Config.specify.output.exe=Specify output file with .exe extension.
+Config.application.jar=Application jar
+Config.application.jar.path=Specify runtime path of the jar relative to the executable.
+Config.chdir.relative='chdir' must be a path relative to the executable.
+Config.chdir.path='chdir' is now a path instead of a boolean, please check the docs.
+Config.manifest=Manifest
+Config.icon=Icon
+Config.jar.arguments=Jar arguments
+Config.error.title=Error title
+Config.download.url=Download URL
+Config.support.url=Support URL
+Config.header.type=Header type
+Config.splash.not.impl.by.console.hdr=Splash screen is not implemented by console header.
+Config.variables=Environment variables
+Config.variables.err=Environment variable assignment should have the form varname=[value][%varref%]...
+Config.priority=Process priority
+
+ClassPath.mainClass=Main class
+ClassPath.or.jar=Specify runtime path of a jar or the classpath.
+ClassPath.path=Classpath
+
+VersionInfo.file.version=File version, should be 'x.x.x.x'
+VersionInfo.txt.file.version=Free form file version
+VersionInfo.file.description=File description
+VersionInfo.copyright=Copyright
+VersionInfo.product.version=Product version, should be 'x.x.x.x'
+VersionInfo.txt.product.version=Free from product version
+VersionInfo.product.name=Product name
+VersionInfo.company.name=Company name
+VersionInfo.internal.name=Internal name
+VersionInfo.internal.name.not.exe=Internal name shouldn't have the .exe extension.
+VersionInfo.original.filename=Original filename
+VersionInfo.original.filename.exe=Original filename should end with the .exe extension.
+
+Jre.min.version=Minimum JRE version should be x.x.x[_xx]
+Jre.max.version=Maximum JRE version should be x.x.x[_xx]
+Jre.specify.jre.min.version.or.path=Specify minimum JRE version and/or bundled JRE path.
+Jre.bundled.path=Bundled JRE path
+Jre.specify.min.version=Specify minimum JRE version.
+Jre.max.greater.than.min=Maximum JRE version must be greater than the minimum.\nTo use a certain JRE version, you may set the min/max range to [1.4.2 - 1.4.2_10] for example.
+Jre.initial.and.max.heap=If you change the initial heap size please also specify the maximum size.
+Jre.initial.heap=Initial heap size must be greater than 0, leave the field blank to use the JVM default.
+Jre.max.heap=Maximum heap size cannot be less than the initial size, leave the field blank to use the JVM default.
+Jre.initial.heap.percent=Initial heap %
+Jre.max.heap.percent=Maximum heap %
+Jre.jdkPreference.invalid=Unrecognised value for JDK preference, should be between 0 and 3 inclusive.
+Jre.jvm.options=JVM arguments
+Jre.jvm.options.unclosed.quotation=JVM arguments contain an unclosed quotation.
+Jre.jvm.options.variable=Invalid environment variable reference.
+
+Msg.startupErr=Startup error message
+Msg.bundledJreErr=Bundled JRE error message
+Msg.jreVersionErr=JRE version error message
+Msg.launcherErr=Launcher error message
+
+SingleInstance.mutexName=Mutex name
+SingleInstance.windowTitle=Window title
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/config/messages_es.properties b/build/windows/launcher/launch4j/src/net/sf/launch4j/config/messages_es.properties
new file mode 100755
index 000000000..5e8659b1f
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/config/messages_es.properties
@@ -0,0 +1,75 @@
+#
+# Launch4j (http://launch4j.sourceforge.net/)
+# Cross-platform Java application wrapper for creating Windows native executables.
+#
+# Copyright (c) 2004, 2007 Grzegorz Kowal, Patricio Martínez Ros
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification,
+# are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+# * Neither the name of the Launch4j nor the names of its contributors
+# may be used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+Splash.splash.file = Fichero de la pantalla de bienvenida
+Splash.splash.timeout = Tiempo de espera de la pantalla de bienvenida
+
+Config.specify.output.exe = Especifique el fichero de salida con extensi\u00F3n .exe.
+Config.application.jar = Aplicaci\u00F3n jar
+Config.application.jar.path = Especifique la ruta del jar relativa al ejecutable.
+Config.chdir.relative = 'Cambiar al directorio' debe ser una ruta relativa al ejecutable.
+Config.chdir.path = 'Cambiar al directorio' ahora es una ruta en lugar de un booleano, por favor consulte la documentaci\u00F3n.
+Config.icon = Icono
+Config.jar.arguments = Argumentos del jar
+Config.error.title = T\u00EDtulo de error
+Config.header.type = Tipo de cabecera
+Config.splash.not.impl.by.console.hdr = La pantalla de bienvenida no est\u00E1 implementada para la cabecera de tipo consola.
+
+VersionInfo.file.version = La versi\u00F3n del fichero, deber\u00EDa ser 'x.x.x.x'
+VersionInfo.txt.file.version = Forma libre de versi\u00F3n del fichero
+VersionInfo.file.description = Descripci\u00F3n del fichero
+VersionInfo.copyright = Copyright
+VersionInfo.product.version = Versi\u00F3n del producto, deber\u00EDa ser 'x.x.x.x'
+VersionInfo.txt.product.version = Forma libre de versi\u00F3n del producto
+VersionInfo.product.name = Nombre del producto
+VersionInfo.company.name = Nombre de la organizaci\u00F3n
+VersionInfo.internal.name = Nombre interno
+VersionInfo.internal.name.not.exe = El nombre interno no deber\u00EDa tener extensi\u00F3n .exe.
+VersionInfo.original.filename = Nombre original del fichero
+VersionInfo.original.filename.exe = El nombre original del fichero debe acabar con extensi\u00F3n .exe.
+Jre.min.version = La versi\u00F3n m\u00EDnima del JRE deber\u00EDa ser x.x.x[_xx]
+Jre.max.version = La versi\u00F3n m\u00E1xima del JRE deber\u00EDa ser x.x.x[_xx]
+Jre.specify.jre.min.version.or.path=Specify minimum JRE version and/or bundled JRE path.
+Jre.bundled.path.rel = La ruta del JRE debe ser relativa al ejecutable.
+Jre.specify.min.version = Especifique la versi\u00F3n m\u00EDnima del JRE.
+Jre.max.greater.than.min = La versi\u00F3n m\u00E1xima del JRE debe ser mayor que la m\u00EDnima.\nPara usar cierta versi\u00F3n del JRE, puede esyablecer el rango m\u00EDnimo/m\u00E1ximo a [1.4.2 - 1.4.2_10], por ejemplo.
+Jre.jvm.options = Argumentos de la JVM
+
+Msg.startupErr=Startup error message
+Msg.bundledJreErr=Bundled JRE error message
+Msg.jreVersionErr=JRE version error message
+Msg.launcherErr=Launcher error message
+
+SingleInstance.mutexName=Mutex name
+SingleInstance.windowTitle=Window title
+
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/form/BasicForm.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/form/BasicForm.java
new file mode 100755
index 000000000..4dadbb983
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/form/BasicForm.java
@@ -0,0 +1,283 @@
+package net.sf.launch4j.form;
+
+import com.jeta.forms.components.separator.TitledSeparator;
+import com.jgoodies.forms.layout.CellConstraints;
+import com.jgoodies.forms.layout.FormLayout;
+import java.awt.BorderLayout;
+import java.awt.Container;
+import java.awt.Dimension;
+import javax.swing.Box;
+import javax.swing.ButtonGroup;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+import javax.swing.JTextField;
+
+public abstract class BasicForm extends JPanel
+{
+ protected final JButton _outfileButton = new JButton();
+ protected final JLabel _outfileLabel = new JLabel();
+ protected final JLabel _iconLabel = new JLabel();
+ protected final JLabel _jarLabel = new JLabel();
+ protected final JButton _jarButton = new JButton();
+ protected final JButton _iconButton = new JButton();
+ protected final JLabel _cmdLineLabel = new JLabel();
+ protected final JLabel _optionsLabel = new JLabel();
+ protected final JLabel _chdirLabel = new JLabel();
+ protected final JLabel _processPriorityLabel = new JLabel();
+ protected final JRadioButton _normalPriorityRadio = new JRadioButton();
+ protected final ButtonGroup _buttongroup1 = new ButtonGroup();
+ protected final JRadioButton _idlePriorityRadio = new JRadioButton();
+ protected final JRadioButton _highPriorityRadio = new JRadioButton();
+ protected final JCheckBox _customProcNameCheck = new JCheckBox();
+ protected final JCheckBox _stayAliveCheck = new JCheckBox();
+ protected final JTextField _cmdLineField = new JTextField();
+ protected final JTextField _chdirField = new JTextField();
+ protected final JTextField _iconField = new JTextField();
+ protected final JCheckBox _dontWrapJarCheck = new JCheckBox();
+ protected final JTextField _jarField = new JTextField();
+ protected final JTextField _outfileField = new JTextField();
+ protected final JLabel _errorTitleLabel = new JLabel();
+ protected final JTextField _errorTitleField = new JTextField();
+ protected final JLabel _downloadUrlLabel = new JLabel();
+ protected final JTextField _downloadUrlField = new JTextField();
+ protected final JLabel _supportUrlLabel = new JLabel();
+ protected final JTextField _supportUrlField = new JTextField();
+ protected final JTextField _manifestField = new JTextField();
+ protected final JButton _manifestButton = new JButton();
+
+ /**
+ * Default constructor
+ */
+ public BasicForm()
+ {
+ initializePanel();
+ }
+
+ /**
+ * Adds fill components to empty cells in the first row and first column of the grid.
+ * This ensures that the grid spacing will be the same as shown in the designer.
+ * @param cols an array of column indices in the first row where fill components should be added.
+ * @param rows an array of row indices in the first column where fill components should be added.
+ */
+ void addFillComponents( Container panel, int[] cols, int[] rows )
+ {
+ Dimension filler = new Dimension(10,10);
+
+ boolean filled_cell_11 = false;
+ CellConstraints cc = new CellConstraints();
+ if ( cols.length > 0 && rows.length > 0 )
+ {
+ if ( cols[0] == 1 && rows[0] == 1 )
+ {
+ /** add a rigid area */
+ panel.add( Box.createRigidArea( filler ), cc.xy(1,1) );
+ filled_cell_11 = true;
+ }
+ }
+
+ for( int index = 0; index < cols.length; index++ )
+ {
+ if ( cols[index] == 1 && filled_cell_11 )
+ {
+ continue;
+ }
+ panel.add( Box.createRigidArea( filler ), cc.xy(cols[index],1) );
+ }
+
+ for( int index = 0; index < rows.length; index++ )
+ {
+ if ( rows[index] == 1 && filled_cell_11 )
+ {
+ continue;
+ }
+ panel.add( Box.createRigidArea( filler ), cc.xy(1,rows[index]) );
+ }
+
+ }
+
+ /**
+ * Helper method to load an image file from the CLASSPATH
+ * @param imageName the package and name of the file to load relative to the CLASSPATH
+ * @return an ImageIcon instance with the specified image file
+ * @throws IllegalArgumentException if the image resource cannot be loaded.
+ */
+ public ImageIcon loadImage( String imageName )
+ {
+ try
+ {
+ ClassLoader classloader = getClass().getClassLoader();
+ java.net.URL url = classloader.getResource( imageName );
+ if ( url != null )
+ {
+ ImageIcon icon = new ImageIcon( url );
+ return icon;
+ }
+ }
+ catch( Exception e )
+ {
+ e.printStackTrace();
+ }
+ throw new IllegalArgumentException( "Unable to load image: " + imageName );
+ }
+
+ public JPanel createPanel()
+ {
+ JPanel jpanel1 = new JPanel();
+ FormLayout formlayout1 = new FormLayout("FILL:7DLU:NONE,RIGHT:MAX(65DLU;DEFAULT):NONE,FILL:3DLU:NONE,FILL:DEFAULT:NONE,FILL:7DLU:NONE,FILL:DEFAULT:NONE,FILL:7DLU:NONE,FILL:DEFAULT:NONE,FILL:DEFAULT:NONE,FILL:DEFAULT:GROW(1.0),FILL:3DLU:NONE,FILL:26PX:NONE,FILL:7DLU:NONE","CENTER:9DLU:NONE,CENTER:DEFAULT:NONE,CENTER:3DLU:NONE,CENTER:DEFAULT:NONE,CENTER:3DLU:NONE,CENTER:DEFAULT:NONE,CENTER:3DLU:NONE,CENTER:DEFAULT:NONE,CENTER:3DLU:NONE,CENTER:DEFAULT:NONE,CENTER:3DLU:NONE,CENTER:DEFAULT:NONE,CENTER:3DLU:NONE,CENTER:DEFAULT:NONE,CENTER:3DLU:NONE,CENTER:DEFAULT:NONE,CENTER:3DLU:NONE,CENTER:DEFAULT:NONE,CENTER:3DLU:NONE,CENTER:DEFAULT:NONE,CENTER:9DLU:NONE,CENTER:DEFAULT:NONE,CENTER:3DLU:NONE,CENTER:DEFAULT:NONE,CENTER:3DLU:NONE,CENTER:DEFAULT:NONE,CENTER:3DLU:NONE,CENTER:DEFAULT:NONE,CENTER:9DLU:NONE");
+ CellConstraints cc = new CellConstraints();
+ jpanel1.setLayout(formlayout1);
+
+ _outfileButton.setIcon(loadImage("images/open16.png"));
+ _outfileButton.setName("outfileButton");
+ jpanel1.add(_outfileButton,cc.xy(12,2));
+
+ _outfileLabel.setIcon(loadImage("images/asterix.gif"));
+ _outfileLabel.setName("outfileLabel");
+ _outfileLabel.setText(Messages.getString("outfile"));
+ jpanel1.add(_outfileLabel,cc.xy(2,2));
+
+ _iconLabel.setName("iconLabel");
+ _iconLabel.setText(Messages.getString("icon"));
+ jpanel1.add(_iconLabel,cc.xy(2,10));
+
+ _jarLabel.setIcon(loadImage("images/asterix.gif"));
+ _jarLabel.setName("jarLabel");
+ _jarLabel.setText(Messages.getString("jar"));
+ jpanel1.add(_jarLabel,cc.xy(2,4));
+
+ _jarButton.setIcon(loadImage("images/open16.png"));
+ _jarButton.setName("jarButton");
+ jpanel1.add(_jarButton,cc.xy(12,4));
+
+ _iconButton.setIcon(loadImage("images/open16.png"));
+ _iconButton.setName("iconButton");
+ jpanel1.add(_iconButton,cc.xy(12,10));
+
+ _cmdLineLabel.setName("cmdLineLabel");
+ _cmdLineLabel.setText(Messages.getString("cmdLine"));
+ _cmdLineLabel.setToolTipText("");
+ jpanel1.add(_cmdLineLabel,cc.xy(2,14));
+
+ _optionsLabel.setName("optionsLabel");
+ _optionsLabel.setText(Messages.getString("options"));
+ jpanel1.add(_optionsLabel,cc.xy(2,18));
+
+ _chdirLabel.setName("chdirLabel");
+ _chdirLabel.setText(Messages.getString("chdir"));
+ jpanel1.add(_chdirLabel,cc.xy(2,12));
+
+ _processPriorityLabel.setName("processPriorityLabel");
+ _processPriorityLabel.setText(Messages.getString("priority"));
+ jpanel1.add(_processPriorityLabel,cc.xy(2,16));
+
+ _normalPriorityRadio.setActionCommand(Messages.getString("normalPriority"));
+ _normalPriorityRadio.setName("normalPriorityRadio");
+ _normalPriorityRadio.setText(Messages.getString("normalPriority"));
+ _buttongroup1.add(_normalPriorityRadio);
+ jpanel1.add(_normalPriorityRadio,cc.xy(4,16));
+
+ _idlePriorityRadio.setActionCommand(Messages.getString("idlePriority"));
+ _idlePriorityRadio.setName("idlePriorityRadio");
+ _idlePriorityRadio.setText(Messages.getString("idlePriority"));
+ _buttongroup1.add(_idlePriorityRadio);
+ jpanel1.add(_idlePriorityRadio,cc.xy(6,16));
+
+ _highPriorityRadio.setActionCommand(Messages.getString("highPriority"));
+ _highPriorityRadio.setName("highPriorityRadio");
+ _highPriorityRadio.setText(Messages.getString("highPriority"));
+ _buttongroup1.add(_highPriorityRadio);
+ jpanel1.add(_highPriorityRadio,cc.xy(8,16));
+
+ _customProcNameCheck.setActionCommand("Custom process name");
+ _customProcNameCheck.setName("customProcNameCheck");
+ _customProcNameCheck.setText(Messages.getString("customProcName"));
+ jpanel1.add(_customProcNameCheck,cc.xywh(4,18,7,1));
+
+ _stayAliveCheck.setActionCommand("Stay alive after launching a GUI application");
+ _stayAliveCheck.setName("stayAliveCheck");
+ _stayAliveCheck.setText(Messages.getString("stayAlive"));
+ jpanel1.add(_stayAliveCheck,cc.xywh(4,20,7,1));
+
+ _cmdLineField.setName("cmdLineField");
+ _cmdLineField.setToolTipText(Messages.getString("cmdLineTip"));
+ jpanel1.add(_cmdLineField,cc.xywh(4,14,7,1));
+
+ _chdirField.setName("chdirField");
+ _chdirField.setToolTipText(Messages.getString("chdirTip"));
+ jpanel1.add(_chdirField,cc.xywh(4,12,7,1));
+
+ _iconField.setName("iconField");
+ _iconField.setToolTipText(Messages.getString("iconTip"));
+ jpanel1.add(_iconField,cc.xywh(4,10,7,1));
+
+ _dontWrapJarCheck.setActionCommand("Don't wrap the jar, launch it only");
+ _dontWrapJarCheck.setName("dontWrapJarCheck");
+ _dontWrapJarCheck.setText(Messages.getString("dontWrapJar"));
+ jpanel1.add(_dontWrapJarCheck,cc.xywh(4,6,7,1));
+
+ _jarField.setName("jarField");
+ _jarField.setToolTipText(Messages.getString("jarTip"));
+ jpanel1.add(_jarField,cc.xywh(4,4,7,1));
+
+ _outfileField.setName("outfileField");
+ _outfileField.setToolTipText(Messages.getString("outfileTip"));
+ jpanel1.add(_outfileField,cc.xywh(4,2,7,1));
+
+ TitledSeparator titledseparator1 = new TitledSeparator();
+ titledseparator1.setText(Messages.getString("downloadAndSupport"));
+ jpanel1.add(titledseparator1,cc.xywh(2,22,11,1));
+
+ _errorTitleLabel.setName("errorTitleLabel");
+ _errorTitleLabel.setText(Messages.getString("errorTitle"));
+ jpanel1.add(_errorTitleLabel,cc.xy(2,24));
+
+ _errorTitleField.setName("errorTitleField");
+ _errorTitleField.setToolTipText(Messages.getString("errorTitleTip"));
+ jpanel1.add(_errorTitleField,cc.xywh(4,24,7,1));
+
+ _downloadUrlLabel.setIcon(loadImage("images/asterix.gif"));
+ _downloadUrlLabel.setName("downloadUrlLabel");
+ _downloadUrlLabel.setText(Messages.getString("downloadUrl"));
+ jpanel1.add(_downloadUrlLabel,cc.xy(2,26));
+
+ _downloadUrlField.setName("downloadUrlField");
+ jpanel1.add(_downloadUrlField,cc.xywh(4,26,7,1));
+
+ _supportUrlLabel.setName("supportUrlLabel");
+ _supportUrlLabel.setText(Messages.getString("supportUrl"));
+ jpanel1.add(_supportUrlLabel,cc.xy(2,28));
+
+ _supportUrlField.setName("supportUrlField");
+ jpanel1.add(_supportUrlField,cc.xywh(4,28,7,1));
+
+ JLabel jlabel1 = new JLabel();
+ jlabel1.setText(Messages.getString("manifest"));
+ jpanel1.add(jlabel1,cc.xy(2,8));
+
+ _manifestField.setName("manifestField");
+ _manifestField.setToolTipText(Messages.getString("manifestTip"));
+ jpanel1.add(_manifestField,cc.xywh(4,8,7,1));
+
+ _manifestButton.setIcon(loadImage("images/open16.png"));
+ _manifestButton.setName("manifestButton");
+ jpanel1.add(_manifestButton,cc.xy(12,8));
+
+ addFillComponents(jpanel1,new int[]{ 1,2,3,4,5,6,7,8,9,10,11,12,13 },new int[]{ 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29 });
+ return jpanel1;
+ }
+
+ /**
+ * Initializer
+ */
+ protected void initializePanel()
+ {
+ setLayout(new BorderLayout());
+ add(createPanel(), BorderLayout.CENTER);
+ }
+
+
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/form/BasicForm.jfrm b/build/windows/launcher/launch4j/src/net/sf/launch4j/form/BasicForm.jfrm
new file mode 100755
index 000000000..1d8a9ad58
Binary files /dev/null and b/build/windows/launcher/launch4j/src/net/sf/launch4j/form/BasicForm.jfrm differ
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/form/ClassPathForm.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/form/ClassPathForm.java
new file mode 100755
index 000000000..9f4f52471
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/form/ClassPathForm.java
@@ -0,0 +1,193 @@
+package net.sf.launch4j.form;
+
+import com.jgoodies.forms.layout.CellConstraints;
+import com.jgoodies.forms.layout.FormLayout;
+import java.awt.BorderLayout;
+import java.awt.Container;
+import java.awt.Dimension;
+import javax.swing.Box;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextField;
+
+public abstract class ClassPathForm extends JPanel
+{
+ protected final JTextField _classpathField = new JTextField();
+ protected final JLabel _classpathFieldLabel = new JLabel();
+ protected final JLabel _classpathListLabel = new JLabel();
+ protected final JList _classpathList = new JList();
+ protected final JLabel _mainclassLabel = new JLabel();
+ protected final JTextField _mainclassField = new JTextField();
+ protected final JButton _acceptClasspathButton = new JButton();
+ protected final JButton _removeClasspathButton = new JButton();
+ protected final JButton _importClasspathButton = new JButton();
+ protected final JButton _classpathUpButton = new JButton();
+ protected final JButton _classpathDownButton = new JButton();
+ protected final JCheckBox _classpathCheck = new JCheckBox();
+ protected final JButton _newClasspathButton = new JButton();
+
+ /**
+ * Default constructor
+ */
+ public ClassPathForm()
+ {
+ initializePanel();
+ }
+
+ /**
+ * Adds fill components to empty cells in the first row and first column of the grid.
+ * This ensures that the grid spacing will be the same as shown in the designer.
+ * @param cols an array of column indices in the first row where fill components should be added.
+ * @param rows an array of row indices in the first column where fill components should be added.
+ */
+ void addFillComponents( Container panel, int[] cols, int[] rows )
+ {
+ Dimension filler = new Dimension(10,10);
+
+ boolean filled_cell_11 = false;
+ CellConstraints cc = new CellConstraints();
+ if ( cols.length > 0 && rows.length > 0 )
+ {
+ if ( cols[0] == 1 && rows[0] == 1 )
+ {
+ /** add a rigid area */
+ panel.add( Box.createRigidArea( filler ), cc.xy(1,1) );
+ filled_cell_11 = true;
+ }
+ }
+
+ for( int index = 0; index < cols.length; index++ )
+ {
+ if ( cols[index] == 1 && filled_cell_11 )
+ {
+ continue;
+ }
+ panel.add( Box.createRigidArea( filler ), cc.xy(cols[index],1) );
+ }
+
+ for( int index = 0; index < rows.length; index++ )
+ {
+ if ( rows[index] == 1 && filled_cell_11 )
+ {
+ continue;
+ }
+ panel.add( Box.createRigidArea( filler ), cc.xy(1,rows[index]) );
+ }
+
+ }
+
+ /**
+ * Helper method to load an image file from the CLASSPATH
+ * @param imageName the package and name of the file to load relative to the CLASSPATH
+ * @return an ImageIcon instance with the specified image file
+ * @throws IllegalArgumentException if the image resource cannot be loaded.
+ */
+ public ImageIcon loadImage( String imageName )
+ {
+ try
+ {
+ ClassLoader classloader = getClass().getClassLoader();
+ java.net.URL url = classloader.getResource( imageName );
+ if ( url != null )
+ {
+ ImageIcon icon = new ImageIcon( url );
+ return icon;
+ }
+ }
+ catch( Exception e )
+ {
+ e.printStackTrace();
+ }
+ throw new IllegalArgumentException( "Unable to load image: " + imageName );
+ }
+
+ public JPanel createPanel()
+ {
+ JPanel jpanel1 = new JPanel();
+ FormLayout formlayout1 = new FormLayout("FILL:7DLU:NONE,RIGHT:MAX(65DLU;DEFAULT):NONE,FILL:3DLU:NONE,FILL:DEFAULT:GROW(1.0),FILL:3DLU:NONE,FILL:DEFAULT:NONE,FILL:3DLU:NONE,FILL:DEFAULT:NONE,FILL:3DLU:NONE,FILL:DEFAULT:NONE,FILL:3DLU:NONE,FILL:26PX:NONE,FILL:7DLU:NONE","CENTER:9DLU:NONE,CENTER:DEFAULT:NONE,CENTER:3DLU:NONE,CENTER:DEFAULT:NONE,CENTER:3DLU:NONE,CENTER:DEFAULT:NONE,CENTER:3DLU:NONE,CENTER:DEFAULT:NONE,CENTER:DEFAULT:GROW(1.0),CENTER:3DLU:NONE,CENTER:DEFAULT:NONE,CENTER:3DLU:NONE,CENTER:DEFAULT:NONE,CENTER:9DLU:NONE");
+ CellConstraints cc = new CellConstraints();
+ jpanel1.setLayout(formlayout1);
+
+ _classpathField.setName("classpathField");
+ jpanel1.add(_classpathField,cc.xywh(4,11,7,1));
+
+ _classpathFieldLabel.setIcon(loadImage("images/asterix.gif"));
+ _classpathFieldLabel.setName("classpathFieldLabel");
+ _classpathFieldLabel.setText(Messages.getString("editClassPath"));
+ jpanel1.add(_classpathFieldLabel,cc.xy(2,11));
+
+ _classpathListLabel.setName("classpathListLabel");
+ _classpathListLabel.setText(Messages.getString("classPath"));
+ jpanel1.add(_classpathListLabel,cc.xy(2,6));
+
+ _classpathList.setName("classpathList");
+ JScrollPane jscrollpane1 = new JScrollPane();
+ jscrollpane1.setViewportView(_classpathList);
+ jscrollpane1.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
+ jscrollpane1.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
+ jpanel1.add(jscrollpane1,cc.xywh(4,6,7,4));
+
+ _mainclassLabel.setIcon(loadImage("images/asterix.gif"));
+ _mainclassLabel.setName("mainclassLabel");
+ _mainclassLabel.setText(Messages.getString("mainClass"));
+ jpanel1.add(_mainclassLabel,cc.xy(2,4));
+
+ _mainclassField.setName("mainclassField");
+ jpanel1.add(_mainclassField,cc.xywh(4,4,7,1));
+
+ _acceptClasspathButton.setActionCommand("Add");
+ _acceptClasspathButton.setIcon(loadImage("images/ok16.png"));
+ _acceptClasspathButton.setName("acceptClasspathButton");
+ _acceptClasspathButton.setText(Messages.getString("accept"));
+ jpanel1.add(_acceptClasspathButton,cc.xy(8,13));
+
+ _removeClasspathButton.setActionCommand("Remove");
+ _removeClasspathButton.setIcon(loadImage("images/cancel16.png"));
+ _removeClasspathButton.setName("removeClasspathButton");
+ _removeClasspathButton.setText(Messages.getString("remove"));
+ jpanel1.add(_removeClasspathButton,cc.xy(10,13));
+
+ _importClasspathButton.setIcon(loadImage("images/open16.png"));
+ _importClasspathButton.setName("importClasspathButton");
+ _importClasspathButton.setToolTipText(Messages.getString("importClassPath"));
+ jpanel1.add(_importClasspathButton,cc.xy(12,4));
+
+ _classpathUpButton.setIcon(loadImage("images/up16.png"));
+ _classpathUpButton.setName("classpathUpButton");
+ jpanel1.add(_classpathUpButton,cc.xy(12,6));
+
+ _classpathDownButton.setIcon(loadImage("images/down16.png"));
+ _classpathDownButton.setName("classpathDownButton");
+ jpanel1.add(_classpathDownButton,cc.xy(12,8));
+
+ _classpathCheck.setActionCommand("Custom classpath");
+ _classpathCheck.setName("classpathCheck");
+ _classpathCheck.setText(Messages.getString("customClassPath"));
+ jpanel1.add(_classpathCheck,cc.xy(4,2));
+
+ _newClasspathButton.setActionCommand("New");
+ _newClasspathButton.setIcon(loadImage("images/new16.png"));
+ _newClasspathButton.setName("newClasspathButton");
+ _newClasspathButton.setText(Messages.getString("new"));
+ jpanel1.add(_newClasspathButton,cc.xy(6,13));
+
+ addFillComponents(jpanel1,new int[]{ 1,2,3,4,5,6,7,8,9,10,11,12,13 },new int[]{ 1,2,3,4,5,6,7,8,9,10,11,12,13,14 });
+ return jpanel1;
+ }
+
+ /**
+ * Initializer
+ */
+ protected void initializePanel()
+ {
+ setLayout(new BorderLayout());
+ add(createPanel(), BorderLayout.CENTER);
+ }
+
+
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/form/ClassPathForm.jfrm b/build/windows/launcher/launch4j/src/net/sf/launch4j/form/ClassPathForm.jfrm
new file mode 100755
index 000000000..764329d2b
Binary files /dev/null and b/build/windows/launcher/launch4j/src/net/sf/launch4j/form/ClassPathForm.jfrm differ
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/form/ConfigForm.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/form/ConfigForm.java
new file mode 100755
index 000000000..b3c6fffed
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/form/ConfigForm.java
@@ -0,0 +1,132 @@
+package net.sf.launch4j.form;
+
+import com.jeta.forms.components.separator.TitledSeparator;
+import com.jgoodies.forms.layout.CellConstraints;
+import com.jgoodies.forms.layout.FormLayout;
+import java.awt.BorderLayout;
+import java.awt.Container;
+import java.awt.Dimension;
+import javax.swing.Box;
+import javax.swing.ImageIcon;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTabbedPane;
+import javax.swing.JTextArea;
+
+public abstract class ConfigForm extends JPanel
+{
+ protected final JTextArea _logTextArea = new JTextArea();
+ protected final TitledSeparator _logSeparator = new TitledSeparator();
+ protected final JTabbedPane _tab = new JTabbedPane();
+
+ /**
+ * Default constructor
+ */
+ public ConfigForm()
+ {
+ initializePanel();
+ }
+
+ /**
+ * Adds fill components to empty cells in the first row and first column of the grid.
+ * This ensures that the grid spacing will be the same as shown in the designer.
+ * @param cols an array of column indices in the first row where fill components should be added.
+ * @param rows an array of row indices in the first column where fill components should be added.
+ */
+ void addFillComponents( Container panel, int[] cols, int[] rows )
+ {
+ Dimension filler = new Dimension(10,10);
+
+ boolean filled_cell_11 = false;
+ CellConstraints cc = new CellConstraints();
+ if ( cols.length > 0 && rows.length > 0 )
+ {
+ if ( cols[0] == 1 && rows[0] == 1 )
+ {
+ /** add a rigid area */
+ panel.add( Box.createRigidArea( filler ), cc.xy(1,1) );
+ filled_cell_11 = true;
+ }
+ }
+
+ for( int index = 0; index < cols.length; index++ )
+ {
+ if ( cols[index] == 1 && filled_cell_11 )
+ {
+ continue;
+ }
+ panel.add( Box.createRigidArea( filler ), cc.xy(cols[index],1) );
+ }
+
+ for( int index = 0; index < rows.length; index++ )
+ {
+ if ( rows[index] == 1 && filled_cell_11 )
+ {
+ continue;
+ }
+ panel.add( Box.createRigidArea( filler ), cc.xy(1,rows[index]) );
+ }
+
+ }
+
+ /**
+ * Helper method to load an image file from the CLASSPATH
+ * @param imageName the package and name of the file to load relative to the CLASSPATH
+ * @return an ImageIcon instance with the specified image file
+ * @throws IllegalArgumentException if the image resource cannot be loaded.
+ */
+ public ImageIcon loadImage( String imageName )
+ {
+ try
+ {
+ ClassLoader classloader = getClass().getClassLoader();
+ java.net.URL url = classloader.getResource( imageName );
+ if ( url != null )
+ {
+ ImageIcon icon = new ImageIcon( url );
+ return icon;
+ }
+ }
+ catch( Exception e )
+ {
+ e.printStackTrace();
+ }
+ throw new IllegalArgumentException( "Unable to load image: " + imageName );
+ }
+
+ public JPanel createPanel()
+ {
+ JPanel jpanel1 = new JPanel();
+ FormLayout formlayout1 = new FormLayout("FILL:7DLU:NONE,FILL:DEFAULT:GROW(1.0),FILL:7DLU:NONE","CENTER:3DLU:NONE,FILL:DEFAULT:NONE,CENTER:3DLU:NONE,CENTER:DEFAULT:NONE,CENTER:3DLU:NONE,FILL:DEFAULT:GROW(1.0),CENTER:9DLU:NONE");
+ CellConstraints cc = new CellConstraints();
+ jpanel1.setLayout(formlayout1);
+
+ _logTextArea.setName("logTextArea");
+ JScrollPane jscrollpane1 = new JScrollPane();
+ jscrollpane1.setViewportView(_logTextArea);
+ jscrollpane1.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
+ jscrollpane1.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
+ jpanel1.add(jscrollpane1,cc.xy(2,6));
+
+ _logSeparator.setName("logSeparator");
+ _logSeparator.setText(Messages.getString("log"));
+ jpanel1.add(_logSeparator,cc.xy(2,4));
+
+ _tab.setName("tab");
+ jpanel1.add(_tab,cc.xywh(1,2,3,1));
+
+ addFillComponents(jpanel1,new int[]{ 1,2,3 },new int[]{ 1,3,4,5,6,7 });
+ return jpanel1;
+ }
+
+ /**
+ * Initializer
+ */
+ protected void initializePanel()
+ {
+ setLayout(new BorderLayout());
+ add(createPanel(), BorderLayout.CENTER);
+ }
+
+
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/form/ConfigForm.jfrm b/build/windows/launcher/launch4j/src/net/sf/launch4j/form/ConfigForm.jfrm
new file mode 100755
index 000000000..2c6721e14
Binary files /dev/null and b/build/windows/launcher/launch4j/src/net/sf/launch4j/form/ConfigForm.jfrm differ
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/form/EnvironmentVarsForm.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/form/EnvironmentVarsForm.java
new file mode 100755
index 000000000..f2b79e6e7
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/form/EnvironmentVarsForm.java
@@ -0,0 +1,127 @@
+package net.sf.launch4j.form;
+
+import com.jgoodies.forms.layout.CellConstraints;
+import com.jgoodies.forms.layout.FormLayout;
+import java.awt.BorderLayout;
+import java.awt.Container;
+import java.awt.Dimension;
+import javax.swing.Box;
+import javax.swing.ImageIcon;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+
+public abstract class EnvironmentVarsForm extends JPanel
+{
+ protected final JTextArea _envVarsTextArea = new JTextArea();
+ protected final JLabel _envVarsLabel = new JLabel();
+
+ /**
+ * Default constructor
+ */
+ public EnvironmentVarsForm()
+ {
+ initializePanel();
+ }
+
+ /**
+ * Adds fill components to empty cells in the first row and first column of the grid.
+ * This ensures that the grid spacing will be the same as shown in the designer.
+ * @param cols an array of column indices in the first row where fill components should be added.
+ * @param rows an array of row indices in the first column where fill components should be added.
+ */
+ void addFillComponents( Container panel, int[] cols, int[] rows )
+ {
+ Dimension filler = new Dimension(10,10);
+
+ boolean filled_cell_11 = false;
+ CellConstraints cc = new CellConstraints();
+ if ( cols.length > 0 && rows.length > 0 )
+ {
+ if ( cols[0] == 1 && rows[0] == 1 )
+ {
+ /** add a rigid area */
+ panel.add( Box.createRigidArea( filler ), cc.xy(1,1) );
+ filled_cell_11 = true;
+ }
+ }
+
+ for( int index = 0; index < cols.length; index++ )
+ {
+ if ( cols[index] == 1 && filled_cell_11 )
+ {
+ continue;
+ }
+ panel.add( Box.createRigidArea( filler ), cc.xy(cols[index],1) );
+ }
+
+ for( int index = 0; index < rows.length; index++ )
+ {
+ if ( rows[index] == 1 && filled_cell_11 )
+ {
+ continue;
+ }
+ panel.add( Box.createRigidArea( filler ), cc.xy(1,rows[index]) );
+ }
+
+ }
+
+ /**
+ * Helper method to load an image file from the CLASSPATH
+ * @param imageName the package and name of the file to load relative to the CLASSPATH
+ * @return an ImageIcon instance with the specified image file
+ * @throws IllegalArgumentException if the image resource cannot be loaded.
+ */
+ public ImageIcon loadImage( String imageName )
+ {
+ try
+ {
+ ClassLoader classloader = getClass().getClassLoader();
+ java.net.URL url = classloader.getResource( imageName );
+ if ( url != null )
+ {
+ ImageIcon icon = new ImageIcon( url );
+ return icon;
+ }
+ }
+ catch( Exception e )
+ {
+ e.printStackTrace();
+ }
+ throw new IllegalArgumentException( "Unable to load image: " + imageName );
+ }
+
+ public JPanel createPanel()
+ {
+ JPanel jpanel1 = new JPanel();
+ FormLayout formlayout1 = new FormLayout("FILL:7DLU:NONE,RIGHT:MAX(65DLU;DEFAULT):NONE,FILL:3DLU:NONE,FILL:DEFAULT:GROW(1.0),FILL:7DLU:NONE","CENTER:9DLU:NONE,FILL:DEFAULT:GROW(1.0),CENTER:9DLU:NONE");
+ CellConstraints cc = new CellConstraints();
+ jpanel1.setLayout(formlayout1);
+
+ _envVarsTextArea.setName("envVarsTextArea");
+ JScrollPane jscrollpane1 = new JScrollPane();
+ jscrollpane1.setViewportView(_envVarsTextArea);
+ jscrollpane1.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
+ jscrollpane1.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
+ jpanel1.add(jscrollpane1,cc.xy(4,2));
+
+ _envVarsLabel.setName("envVarsLabel");
+ _envVarsLabel.setText(Messages.getString("setVariables"));
+ jpanel1.add(_envVarsLabel,new CellConstraints(2,2,1,1,CellConstraints.DEFAULT,CellConstraints.TOP));
+
+ addFillComponents(jpanel1,new int[]{ 1,2,3,4,5 },new int[]{ 1,2,3 });
+ return jpanel1;
+ }
+
+ /**
+ * Initializer
+ */
+ protected void initializePanel()
+ {
+ setLayout(new BorderLayout());
+ add(createPanel(), BorderLayout.CENTER);
+ }
+
+
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/form/EnvironmentVarsForm.jfrm b/build/windows/launcher/launch4j/src/net/sf/launch4j/form/EnvironmentVarsForm.jfrm
new file mode 100755
index 000000000..6e89ec4d1
Binary files /dev/null and b/build/windows/launcher/launch4j/src/net/sf/launch4j/form/EnvironmentVarsForm.jfrm differ
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/form/HeaderForm.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/form/HeaderForm.java
new file mode 100755
index 000000000..91c40024a
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/form/HeaderForm.java
@@ -0,0 +1,171 @@
+package net.sf.launch4j.form;
+
+import com.jeta.forms.components.separator.TitledSeparator;
+import com.jgoodies.forms.layout.CellConstraints;
+import com.jgoodies.forms.layout.FormLayout;
+import java.awt.BorderLayout;
+import java.awt.Container;
+import java.awt.Dimension;
+import javax.swing.Box;
+import javax.swing.ButtonGroup;
+import javax.swing.ImageIcon;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+
+public abstract class HeaderForm extends JPanel
+{
+ protected final JLabel _headerTypeLabel = new JLabel();
+ protected final JRadioButton _guiHeaderRadio = new JRadioButton();
+ protected final ButtonGroup _headerButtonGroup = new ButtonGroup();
+ protected final JRadioButton _consoleHeaderRadio = new JRadioButton();
+ protected final JTextArea _headerObjectsTextArea = new JTextArea();
+ protected final JTextArea _libsTextArea = new JTextArea();
+ protected final JCheckBox _headerObjectsCheck = new JCheckBox();
+ protected final JCheckBox _libsCheck = new JCheckBox();
+ protected final TitledSeparator _linkerOptionsSeparator = new TitledSeparator();
+
+ /**
+ * Default constructor
+ */
+ public HeaderForm()
+ {
+ initializePanel();
+ }
+
+ /**
+ * Adds fill components to empty cells in the first row and first column of the grid.
+ * This ensures that the grid spacing will be the same as shown in the designer.
+ * @param cols an array of column indices in the first row where fill components should be added.
+ * @param rows an array of row indices in the first column where fill components should be added.
+ */
+ void addFillComponents( Container panel, int[] cols, int[] rows )
+ {
+ Dimension filler = new Dimension(10,10);
+
+ boolean filled_cell_11 = false;
+ CellConstraints cc = new CellConstraints();
+ if ( cols.length > 0 && rows.length > 0 )
+ {
+ if ( cols[0] == 1 && rows[0] == 1 )
+ {
+ /** add a rigid area */
+ panel.add( Box.createRigidArea( filler ), cc.xy(1,1) );
+ filled_cell_11 = true;
+ }
+ }
+
+ for( int index = 0; index < cols.length; index++ )
+ {
+ if ( cols[index] == 1 && filled_cell_11 )
+ {
+ continue;
+ }
+ panel.add( Box.createRigidArea( filler ), cc.xy(cols[index],1) );
+ }
+
+ for( int index = 0; index < rows.length; index++ )
+ {
+ if ( rows[index] == 1 && filled_cell_11 )
+ {
+ continue;
+ }
+ panel.add( Box.createRigidArea( filler ), cc.xy(1,rows[index]) );
+ }
+
+ }
+
+ /**
+ * Helper method to load an image file from the CLASSPATH
+ * @param imageName the package and name of the file to load relative to the CLASSPATH
+ * @return an ImageIcon instance with the specified image file
+ * @throws IllegalArgumentException if the image resource cannot be loaded.
+ */
+ public ImageIcon loadImage( String imageName )
+ {
+ try
+ {
+ ClassLoader classloader = getClass().getClassLoader();
+ java.net.URL url = classloader.getResource( imageName );
+ if ( url != null )
+ {
+ ImageIcon icon = new ImageIcon( url );
+ return icon;
+ }
+ }
+ catch( Exception e )
+ {
+ e.printStackTrace();
+ }
+ throw new IllegalArgumentException( "Unable to load image: " + imageName );
+ }
+
+ public JPanel createPanel()
+ {
+ JPanel jpanel1 = new JPanel();
+ FormLayout formlayout1 = new FormLayout("FILL:7DLU:NONE,RIGHT:MAX(65DLU;DEFAULT):NONE,FILL:3DLU:NONE,FILL:DEFAULT:NONE,FILL:7DLU:NONE,FILL:DEFAULT:NONE,FILL:DEFAULT:GROW(1.0),FILL:7DLU:NONE","CENTER:9DLU:NONE,CENTER:DEFAULT:NONE,CENTER:9DLU:NONE,CENTER:DEFAULT:NONE,CENTER:3DLU:NONE,FILL:DEFAULT:GROW(0.2),CENTER:3DLU:NONE,FILL:DEFAULT:GROW(1.0),CENTER:9DLU:NONE");
+ CellConstraints cc = new CellConstraints();
+ jpanel1.setLayout(formlayout1);
+
+ _headerTypeLabel.setName("headerTypeLabel");
+ _headerTypeLabel.setText(Messages.getString("headerType"));
+ jpanel1.add(_headerTypeLabel,cc.xy(2,2));
+
+ _guiHeaderRadio.setActionCommand("GUI");
+ _guiHeaderRadio.setName("guiHeaderRadio");
+ _guiHeaderRadio.setText(Messages.getString("gui"));
+ _headerButtonGroup.add(_guiHeaderRadio);
+ jpanel1.add(_guiHeaderRadio,cc.xy(4,2));
+
+ _consoleHeaderRadio.setActionCommand("Console");
+ _consoleHeaderRadio.setName("consoleHeaderRadio");
+ _consoleHeaderRadio.setText(Messages.getString("console"));
+ _headerButtonGroup.add(_consoleHeaderRadio);
+ jpanel1.add(_consoleHeaderRadio,cc.xy(6,2));
+
+ _headerObjectsTextArea.setName("headerObjectsTextArea");
+ JScrollPane jscrollpane1 = new JScrollPane();
+ jscrollpane1.setViewportView(_headerObjectsTextArea);
+ jscrollpane1.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
+ jscrollpane1.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
+ jpanel1.add(jscrollpane1,cc.xywh(4,6,4,1));
+
+ _libsTextArea.setName("libsTextArea");
+ JScrollPane jscrollpane2 = new JScrollPane();
+ jscrollpane2.setViewportView(_libsTextArea);
+ jscrollpane2.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
+ jscrollpane2.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
+ jpanel1.add(jscrollpane2,cc.xywh(4,8,4,1));
+
+ _headerObjectsCheck.setActionCommand("Object files");
+ _headerObjectsCheck.setName("headerObjectsCheck");
+ _headerObjectsCheck.setText(Messages.getString("objectFiles"));
+ jpanel1.add(_headerObjectsCheck,new CellConstraints(2,6,1,1,CellConstraints.DEFAULT,CellConstraints.TOP));
+
+ _libsCheck.setActionCommand("w32api");
+ _libsCheck.setName("libsCheck");
+ _libsCheck.setText(Messages.getString("libs"));
+ jpanel1.add(_libsCheck,new CellConstraints(2,8,1,1,CellConstraints.DEFAULT,CellConstraints.TOP));
+
+ _linkerOptionsSeparator.setName("linkerOptionsSeparator");
+ _linkerOptionsSeparator.setText(Messages.getString("linkerOptions"));
+ jpanel1.add(_linkerOptionsSeparator,cc.xywh(2,4,6,1));
+
+ addFillComponents(jpanel1,new int[]{ 1,2,3,4,5,6,7,8 },new int[]{ 1,2,3,4,5,6,7,8,9 });
+ return jpanel1;
+ }
+
+ /**
+ * Initializer
+ */
+ protected void initializePanel()
+ {
+ setLayout(new BorderLayout());
+ add(createPanel(), BorderLayout.CENTER);
+ }
+
+
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/form/HeaderForm.jfrm b/build/windows/launcher/launch4j/src/net/sf/launch4j/form/HeaderForm.jfrm
new file mode 100755
index 000000000..a7cbed144
Binary files /dev/null and b/build/windows/launcher/launch4j/src/net/sf/launch4j/form/HeaderForm.jfrm differ
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/form/JreForm.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/form/JreForm.java
new file mode 100755
index 000000000..ed16c50b6
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/form/JreForm.java
@@ -0,0 +1,266 @@
+package net.sf.launch4j.form;
+
+import com.jgoodies.forms.layout.CellConstraints;
+import com.jgoodies.forms.layout.FormLayout;
+import java.awt.BorderLayout;
+import java.awt.Container;
+import java.awt.Dimension;
+import javax.swing.Box;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.JTextField;
+
+public abstract class JreForm extends JPanel
+{
+ protected final JLabel _jrePathLabel = new JLabel();
+ protected final JLabel _jreMinLabel = new JLabel();
+ protected final JLabel _jreMaxLabel = new JLabel();
+ protected final JLabel _jvmOptionsTextLabel = new JLabel();
+ protected final JTextField _jrePathField = new JTextField();
+ protected final JTextField _jreMinField = new JTextField();
+ protected final JTextField _jreMaxField = new JTextField();
+ protected final JTextArea _jvmOptionsTextArea = new JTextArea();
+ protected final JLabel _initialHeapSizeLabel = new JLabel();
+ protected final JLabel _maxHeapSizeLabel = new JLabel();
+ protected final JTextField _initialHeapSizeField = new JTextField();
+ protected final JTextField _maxHeapSizeField = new JTextField();
+ protected final JComboBox _varCombo = new JComboBox();
+ protected final JButton _propertyButton = new JButton();
+ protected final JButton _optionButton = new JButton();
+ protected final JButton _envPropertyButton = new JButton();
+ protected final JButton _envOptionButton = new JButton();
+ protected final JTextField _envVarField = new JTextField();
+ protected final JTextField _maxHeapPercentField = new JTextField();
+ protected final JTextField _initialHeapPercentField = new JTextField();
+ protected final JComboBox _jdkPreferenceCombo = new JComboBox();
+
+ /**
+ * Default constructor
+ */
+ public JreForm()
+ {
+ initializePanel();
+ }
+
+ /**
+ * Adds fill components to empty cells in the first row and first column of the grid.
+ * This ensures that the grid spacing will be the same as shown in the designer.
+ * @param cols an array of column indices in the first row where fill components should be added.
+ * @param rows an array of row indices in the first column where fill components should be added.
+ */
+ void addFillComponents( Container panel, int[] cols, int[] rows )
+ {
+ Dimension filler = new Dimension(10,10);
+
+ boolean filled_cell_11 = false;
+ CellConstraints cc = new CellConstraints();
+ if ( cols.length > 0 && rows.length > 0 )
+ {
+ if ( cols[0] == 1 && rows[0] == 1 )
+ {
+ /** add a rigid area */
+ panel.add( Box.createRigidArea( filler ), cc.xy(1,1) );
+ filled_cell_11 = true;
+ }
+ }
+
+ for( int index = 0; index < cols.length; index++ )
+ {
+ if ( cols[index] == 1 && filled_cell_11 )
+ {
+ continue;
+ }
+ panel.add( Box.createRigidArea( filler ), cc.xy(cols[index],1) );
+ }
+
+ for( int index = 0; index < rows.length; index++ )
+ {
+ if ( rows[index] == 1 && filled_cell_11 )
+ {
+ continue;
+ }
+ panel.add( Box.createRigidArea( filler ), cc.xy(1,rows[index]) );
+ }
+
+ }
+
+ /**
+ * Helper method to load an image file from the CLASSPATH
+ * @param imageName the package and name of the file to load relative to the CLASSPATH
+ * @return an ImageIcon instance with the specified image file
+ * @throws IllegalArgumentException if the image resource cannot be loaded.
+ */
+ public ImageIcon loadImage( String imageName )
+ {
+ try
+ {
+ ClassLoader classloader = getClass().getClassLoader();
+ java.net.URL url = classloader.getResource( imageName );
+ if ( url != null )
+ {
+ ImageIcon icon = new ImageIcon( url );
+ return icon;
+ }
+ }
+ catch( Exception e )
+ {
+ e.printStackTrace();
+ }
+ throw new IllegalArgumentException( "Unable to load image: " + imageName );
+ }
+
+ public JPanel createPanel()
+ {
+ JPanel jpanel1 = new JPanel();
+ FormLayout formlayout1 = new FormLayout("FILL:7DLU:NONE,RIGHT:MAX(65DLU;DEFAULT):NONE,FILL:3DLU:NONE,FILL:60DLU:NONE,FILL:3DLU:NONE,FILL:DEFAULT:NONE,FILL:7DLU:NONE,FILL:60DLU:NONE,FILL:3DLU:NONE,FILL:DEFAULT:GROW(1.0),FILL:7DLU:NONE","CENTER:9DLU:NONE,CENTER:DEFAULT:NONE,CENTER:3DLU:NONE,CENTER:DEFAULT:NONE,CENTER:3DLU:NONE,CENTER:DEFAULT:NONE,CENTER:3DLU:NONE,CENTER:DEFAULT:NONE,CENTER:3DLU:NONE,CENTER:DEFAULT:NONE,CENTER:3DLU:NONE,FILL:50DLU:GROW(1.0),CENTER:3DLU:NONE,CENTER:DEFAULT:NONE,CENTER:9DLU:NONE");
+ CellConstraints cc = new CellConstraints();
+ jpanel1.setLayout(formlayout1);
+
+ _jrePathLabel.setName("jrePathLabel");
+ _jrePathLabel.setText(Messages.getString("jrePath"));
+ jpanel1.add(_jrePathLabel,cc.xy(2,2));
+
+ _jreMinLabel.setName("jreMinLabel");
+ _jreMinLabel.setText(Messages.getString("jreMin"));
+ jpanel1.add(_jreMinLabel,cc.xy(2,4));
+
+ _jreMaxLabel.setName("jreMaxLabel");
+ _jreMaxLabel.setText(Messages.getString("jreMax"));
+ jpanel1.add(_jreMaxLabel,cc.xy(2,6));
+
+ _jvmOptionsTextLabel.setName("jvmOptionsTextLabel");
+ _jvmOptionsTextLabel.setText(Messages.getString("jvmOptions"));
+ jpanel1.add(_jvmOptionsTextLabel,new CellConstraints(2,12,1,1,CellConstraints.DEFAULT,CellConstraints.TOP));
+
+ _jrePathField.setName("jrePathField");
+ _jrePathField.setToolTipText(Messages.getString("jrePathTip"));
+ jpanel1.add(_jrePathField,cc.xywh(4,2,7,1));
+
+ _jreMinField.setName("jreMinField");
+ jpanel1.add(_jreMinField,cc.xy(4,4));
+
+ _jreMaxField.setName("jreMaxField");
+ jpanel1.add(_jreMaxField,cc.xy(4,6));
+
+ _jvmOptionsTextArea.setName("jvmOptionsTextArea");
+ _jvmOptionsTextArea.setToolTipText(Messages.getString("jvmOptionsTip"));
+ JScrollPane jscrollpane1 = new JScrollPane();
+ jscrollpane1.setViewportView(_jvmOptionsTextArea);
+ jscrollpane1.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
+ jscrollpane1.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
+ jpanel1.add(jscrollpane1,cc.xywh(4,12,7,1));
+
+ _initialHeapSizeLabel.setName("initialHeapSizeLabel");
+ _initialHeapSizeLabel.setText(Messages.getString("initialHeapSize"));
+ jpanel1.add(_initialHeapSizeLabel,cc.xy(2,8));
+
+ _maxHeapSizeLabel.setName("maxHeapSizeLabel");
+ _maxHeapSizeLabel.setText(Messages.getString("maxHeapSize"));
+ jpanel1.add(_maxHeapSizeLabel,cc.xy(2,10));
+
+ JLabel jlabel1 = new JLabel();
+ jlabel1.setText("MB");
+ jpanel1.add(jlabel1,cc.xy(6,8));
+
+ JLabel jlabel2 = new JLabel();
+ jlabel2.setText("MB");
+ jpanel1.add(jlabel2,cc.xy(6,10));
+
+ _initialHeapSizeField.setName("initialHeapSizeField");
+ jpanel1.add(_initialHeapSizeField,cc.xy(4,8));
+
+ _maxHeapSizeField.setName("maxHeapSizeField");
+ jpanel1.add(_maxHeapSizeField,cc.xy(4,10));
+
+ jpanel1.add(createPanel1(),cc.xywh(2,14,9,1));
+ _maxHeapPercentField.setName("maxHeapPercentField");
+ jpanel1.add(_maxHeapPercentField,cc.xy(8,10));
+
+ _initialHeapPercentField.setName("initialHeapPercentField");
+ jpanel1.add(_initialHeapPercentField,cc.xy(8,8));
+
+ _jdkPreferenceCombo.setName("jdkPreferenceCombo");
+ jpanel1.add(_jdkPreferenceCombo,cc.xywh(8,4,3,1));
+
+ JLabel jlabel3 = new JLabel();
+ jlabel3.setText(Messages.getString("freeMemory"));
+ jpanel1.add(jlabel3,cc.xy(10,8));
+
+ JLabel jlabel4 = new JLabel();
+ jlabel4.setText(Messages.getString("freeMemory"));
+ jpanel1.add(jlabel4,cc.xy(10,10));
+
+ addFillComponents(jpanel1,new int[]{ 1,2,3,4,5,6,7,8,9,10,11 },new int[]{ 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 });
+ return jpanel1;
+ }
+
+ public JPanel createPanel1()
+ {
+ JPanel jpanel1 = new JPanel();
+ FormLayout formlayout1 = new FormLayout("RIGHT:MAX(65DLU;DEFAULT):NONE,FILL:3DLU:NONE,FILL:DEFAULT:GROW(1.0),FILL:3DLU:NONE,FILL:DEFAULT:NONE,FILL:3DLU:NONE,FILL:DEFAULT:NONE","CENTER:DEFAULT:NONE,CENTER:3DLU:NONE,CENTER:DEFAULT:NONE");
+ CellConstraints cc = new CellConstraints();
+ jpanel1.setLayout(formlayout1);
+
+ _varCombo.setName("varCombo");
+ jpanel1.add(_varCombo,cc.xy(3,1));
+
+ _propertyButton.setActionCommand("Add");
+ _propertyButton.setIcon(loadImage("images/edit_add16.png"));
+ _propertyButton.setName("propertyButton");
+ _propertyButton.setText(Messages.getString("property"));
+ _propertyButton.setToolTipText(Messages.getString("propertyTip"));
+ jpanel1.add(_propertyButton,cc.xy(5,1));
+
+ _optionButton.setActionCommand("Add");
+ _optionButton.setIcon(loadImage("images/edit_add16.png"));
+ _optionButton.setName("optionButton");
+ _optionButton.setText(Messages.getString("option"));
+ _optionButton.setToolTipText(Messages.getString("optionTip"));
+ jpanel1.add(_optionButton,cc.xy(7,1));
+
+ _envPropertyButton.setActionCommand("Add");
+ _envPropertyButton.setIcon(loadImage("images/edit_add16.png"));
+ _envPropertyButton.setName("envPropertyButton");
+ _envPropertyButton.setText(Messages.getString("property"));
+ _envPropertyButton.setToolTipText(Messages.getString("propertyTip"));
+ jpanel1.add(_envPropertyButton,cc.xy(5,3));
+
+ JLabel jlabel1 = new JLabel();
+ jlabel1.setText(Messages.getString("varsAndRegistry"));
+ jpanel1.add(jlabel1,cc.xy(1,1));
+
+ JLabel jlabel2 = new JLabel();
+ jlabel2.setIcon(loadImage("images/asterix.gif"));
+ jlabel2.setText(Messages.getString("envVar"));
+ jpanel1.add(jlabel2,cc.xy(1,3));
+
+ _envOptionButton.setActionCommand("Add");
+ _envOptionButton.setIcon(loadImage("images/edit_add16.png"));
+ _envOptionButton.setName("envOptionButton");
+ _envOptionButton.setText(Messages.getString("option"));
+ _envOptionButton.setToolTipText(Messages.getString("optionTip"));
+ jpanel1.add(_envOptionButton,cc.xy(7,3));
+
+ _envVarField.setName("envVarField");
+ jpanel1.add(_envVarField,cc.xy(3,3));
+
+ addFillComponents(jpanel1,new int[]{ 2,4,6 },new int[]{ 2 });
+ return jpanel1;
+ }
+
+ /**
+ * Initializer
+ */
+ protected void initializePanel()
+ {
+ setLayout(new BorderLayout());
+ add(createPanel(), BorderLayout.CENTER);
+ }
+
+
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/form/JreForm.jfrm b/build/windows/launcher/launch4j/src/net/sf/launch4j/form/JreForm.jfrm
new file mode 100755
index 000000000..1e61237e0
Binary files /dev/null and b/build/windows/launcher/launch4j/src/net/sf/launch4j/form/JreForm.jfrm differ
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/form/Messages.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/form/Messages.java
new file mode 100755
index 000000000..aaf995f80
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/form/Messages.java
@@ -0,0 +1,55 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package net.sf.launch4j.form;
+
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+class Messages {
+ private static final String BUNDLE_NAME = "net.sf.launch4j.form.messages";
+
+ private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle
+ .getBundle(BUNDLE_NAME);
+
+ private Messages() {
+ }
+
+ public static String getString(String key) {
+ try {
+ return RESOURCE_BUNDLE.getString(key);
+ } catch (MissingResourceException e) {
+ return '!' + key + '!';
+ }
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/form/MessagesForm.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/form/MessagesForm.java
new file mode 100755
index 000000000..f2e8723da
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/form/MessagesForm.java
@@ -0,0 +1,183 @@
+package net.sf.launch4j.form;
+
+import com.jgoodies.forms.layout.CellConstraints;
+import com.jgoodies.forms.layout.FormLayout;
+import java.awt.BorderLayout;
+import java.awt.Container;
+import java.awt.Dimension;
+import javax.swing.Box;
+import javax.swing.ImageIcon;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+
+public abstract class MessagesForm extends JPanel
+{
+ protected final JTextArea _startupErrTextArea = new JTextArea();
+ protected final JTextArea _bundledJreErrTextArea = new JTextArea();
+ protected final JTextArea _jreVersionErrTextArea = new JTextArea();
+ protected final JTextArea _launcherErrTextArea = new JTextArea();
+ protected final JCheckBox _messagesCheck = new JCheckBox();
+ protected final JTextArea _instanceAlreadyExistsMsgTextArea = new JTextArea();
+
+ /**
+ * Default constructor
+ */
+ public MessagesForm()
+ {
+ initializePanel();
+ }
+
+ /**
+ * Adds fill components to empty cells in the first row and first column of the grid.
+ * This ensures that the grid spacing will be the same as shown in the designer.
+ * @param cols an array of column indices in the first row where fill components should be added.
+ * @param rows an array of row indices in the first column where fill components should be added.
+ */
+ void addFillComponents( Container panel, int[] cols, int[] rows )
+ {
+ Dimension filler = new Dimension(10,10);
+
+ boolean filled_cell_11 = false;
+ CellConstraints cc = new CellConstraints();
+ if ( cols.length > 0 && rows.length > 0 )
+ {
+ if ( cols[0] == 1 && rows[0] == 1 )
+ {
+ /** add a rigid area */
+ panel.add( Box.createRigidArea( filler ), cc.xy(1,1) );
+ filled_cell_11 = true;
+ }
+ }
+
+ for( int index = 0; index < cols.length; index++ )
+ {
+ if ( cols[index] == 1 && filled_cell_11 )
+ {
+ continue;
+ }
+ panel.add( Box.createRigidArea( filler ), cc.xy(cols[index],1) );
+ }
+
+ for( int index = 0; index < rows.length; index++ )
+ {
+ if ( rows[index] == 1 && filled_cell_11 )
+ {
+ continue;
+ }
+ panel.add( Box.createRigidArea( filler ), cc.xy(1,rows[index]) );
+ }
+
+ }
+
+ /**
+ * Helper method to load an image file from the CLASSPATH
+ * @param imageName the package and name of the file to load relative to the CLASSPATH
+ * @return an ImageIcon instance with the specified image file
+ * @throws IllegalArgumentException if the image resource cannot be loaded.
+ */
+ public ImageIcon loadImage( String imageName )
+ {
+ try
+ {
+ ClassLoader classloader = getClass().getClassLoader();
+ java.net.URL url = classloader.getResource( imageName );
+ if ( url != null )
+ {
+ ImageIcon icon = new ImageIcon( url );
+ return icon;
+ }
+ }
+ catch( Exception e )
+ {
+ e.printStackTrace();
+ }
+ throw new IllegalArgumentException( "Unable to load image: " + imageName );
+ }
+
+ public JPanel createPanel()
+ {
+ JPanel jpanel1 = new JPanel();
+ FormLayout formlayout1 = new FormLayout("FILL:7DLU:NONE,RIGHT:MAX(65DLU;DEFAULT):NONE,FILL:3DLU:NONE,FILL:DEFAULT:GROW(1.0),FILL:7DLU:NONE","CENTER:9DLU:NONE,CENTER:DEFAULT:NONE,CENTER:3DLU:NONE,FILL:DEFAULT:GROW(1.0),CENTER:3DLU:NONE,FILL:DEFAULT:GROW(1.0),CENTER:3DLU:NONE,FILL:DEFAULT:GROW(1.0),CENTER:3DLU:NONE,FILL:DEFAULT:GROW(1.0),CENTER:3DLU:NONE,FILL:DEFAULT:GROW(1.0),CENTER:9DLU:NONE");
+ CellConstraints cc = new CellConstraints();
+ jpanel1.setLayout(formlayout1);
+
+ _startupErrTextArea.setName("startupErrTextArea");
+ JScrollPane jscrollpane1 = new JScrollPane();
+ jscrollpane1.setViewportView(_startupErrTextArea);
+ jscrollpane1.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
+ jscrollpane1.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
+ jpanel1.add(jscrollpane1,cc.xy(4,4));
+
+ _bundledJreErrTextArea.setName("bundledJreErrTextArea");
+ JScrollPane jscrollpane2 = new JScrollPane();
+ jscrollpane2.setViewportView(_bundledJreErrTextArea);
+ jscrollpane2.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
+ jscrollpane2.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
+ jpanel1.add(jscrollpane2,cc.xy(4,6));
+
+ _jreVersionErrTextArea.setName("jreVersionErrTextArea");
+ _jreVersionErrTextArea.setToolTipText(Messages.getString("jreVersionErrTip"));
+ JScrollPane jscrollpane3 = new JScrollPane();
+ jscrollpane3.setViewportView(_jreVersionErrTextArea);
+ jscrollpane3.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
+ jscrollpane3.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
+ jpanel1.add(jscrollpane3,cc.xy(4,8));
+
+ _launcherErrTextArea.setName("launcherErrTextArea");
+ JScrollPane jscrollpane4 = new JScrollPane();
+ jscrollpane4.setViewportView(_launcherErrTextArea);
+ jscrollpane4.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
+ jscrollpane4.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
+ jpanel1.add(jscrollpane4,cc.xy(4,10));
+
+ JLabel jlabel1 = new JLabel();
+ jlabel1.setText(Messages.getString("startupErr"));
+ jpanel1.add(jlabel1,new CellConstraints(2,4,1,1,CellConstraints.DEFAULT,CellConstraints.TOP));
+
+ JLabel jlabel2 = new JLabel();
+ jlabel2.setText(Messages.getString("bundledJreErr"));
+ jpanel1.add(jlabel2,new CellConstraints(2,6,1,1,CellConstraints.DEFAULT,CellConstraints.TOP));
+
+ JLabel jlabel3 = new JLabel();
+ jlabel3.setText(Messages.getString("jreVersionErr"));
+ jpanel1.add(jlabel3,new CellConstraints(2,8,1,1,CellConstraints.DEFAULT,CellConstraints.TOP));
+
+ JLabel jlabel4 = new JLabel();
+ jlabel4.setText(Messages.getString("launcherErr"));
+ jpanel1.add(jlabel4,new CellConstraints(2,10,1,1,CellConstraints.DEFAULT,CellConstraints.TOP));
+
+ _messagesCheck.setActionCommand("Add version information");
+ _messagesCheck.setName("messagesCheck");
+ _messagesCheck.setText(Messages.getString("addMessages"));
+ jpanel1.add(_messagesCheck,cc.xy(4,2));
+
+ JLabel jlabel5 = new JLabel();
+ jlabel5.setText(Messages.getString("instanceAlreadyExistsMsg"));
+ jpanel1.add(jlabel5,new CellConstraints(2,12,1,1,CellConstraints.DEFAULT,CellConstraints.TOP));
+
+ _instanceAlreadyExistsMsgTextArea.setName("instanceAlreadyExistsMsgTextArea");
+ _instanceAlreadyExistsMsgTextArea.setToolTipText(Messages.getString("instanceAlreadyExistsMsgTip"));
+ JScrollPane jscrollpane5 = new JScrollPane();
+ jscrollpane5.setViewportView(_instanceAlreadyExistsMsgTextArea);
+ jscrollpane5.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
+ jscrollpane5.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
+ jpanel1.add(jscrollpane5,cc.xy(4,12));
+
+ addFillComponents(jpanel1,new int[]{ 1,2,3,4,5 },new int[]{ 1,2,3,4,5,6,7,8,9,10,11,12,13 });
+ return jpanel1;
+ }
+
+ /**
+ * Initializer
+ */
+ protected void initializePanel()
+ {
+ setLayout(new BorderLayout());
+ add(createPanel(), BorderLayout.CENTER);
+ }
+
+
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/form/MessagesForm.jfrm b/build/windows/launcher/launch4j/src/net/sf/launch4j/form/MessagesForm.jfrm
new file mode 100755
index 000000000..e8044dfd7
Binary files /dev/null and b/build/windows/launcher/launch4j/src/net/sf/launch4j/form/MessagesForm.jfrm differ
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/form/SingleInstanceForm.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/form/SingleInstanceForm.java
new file mode 100755
index 000000000..2bfe724a6
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/form/SingleInstanceForm.java
@@ -0,0 +1,141 @@
+package net.sf.launch4j.form;
+
+import com.jgoodies.forms.layout.CellConstraints;
+import com.jgoodies.forms.layout.FormLayout;
+import java.awt.BorderLayout;
+import java.awt.Container;
+import java.awt.Dimension;
+import javax.swing.Box;
+import javax.swing.ImageIcon;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+
+public abstract class SingleInstanceForm extends JPanel
+{
+ protected final JLabel _splashFileLabel = new JLabel();
+ protected final JTextField _mutexNameField = new JTextField();
+ protected final JCheckBox _singleInstanceCheck = new JCheckBox();
+ protected final JTextField _windowTitleField = new JTextField();
+ protected final JLabel _splashFileLabel1 = new JLabel();
+
+ /**
+ * Default constructor
+ */
+ public SingleInstanceForm()
+ {
+ initializePanel();
+ }
+
+ /**
+ * Adds fill components to empty cells in the first row and first column of the grid.
+ * This ensures that the grid spacing will be the same as shown in the designer.
+ * @param cols an array of column indices in the first row where fill components should be added.
+ * @param rows an array of row indices in the first column where fill components should be added.
+ */
+ void addFillComponents( Container panel, int[] cols, int[] rows )
+ {
+ Dimension filler = new Dimension(10,10);
+
+ boolean filled_cell_11 = false;
+ CellConstraints cc = new CellConstraints();
+ if ( cols.length > 0 && rows.length > 0 )
+ {
+ if ( cols[0] == 1 && rows[0] == 1 )
+ {
+ /** add a rigid area */
+ panel.add( Box.createRigidArea( filler ), cc.xy(1,1) );
+ filled_cell_11 = true;
+ }
+ }
+
+ for( int index = 0; index < cols.length; index++ )
+ {
+ if ( cols[index] == 1 && filled_cell_11 )
+ {
+ continue;
+ }
+ panel.add( Box.createRigidArea( filler ), cc.xy(cols[index],1) );
+ }
+
+ for( int index = 0; index < rows.length; index++ )
+ {
+ if ( rows[index] == 1 && filled_cell_11 )
+ {
+ continue;
+ }
+ panel.add( Box.createRigidArea( filler ), cc.xy(1,rows[index]) );
+ }
+
+ }
+
+ /**
+ * Helper method to load an image file from the CLASSPATH
+ * @param imageName the package and name of the file to load relative to the CLASSPATH
+ * @return an ImageIcon instance with the specified image file
+ * @throws IllegalArgumentException if the image resource cannot be loaded.
+ */
+ public ImageIcon loadImage( String imageName )
+ {
+ try
+ {
+ ClassLoader classloader = getClass().getClassLoader();
+ java.net.URL url = classloader.getResource( imageName );
+ if ( url != null )
+ {
+ ImageIcon icon = new ImageIcon( url );
+ return icon;
+ }
+ }
+ catch( Exception e )
+ {
+ e.printStackTrace();
+ }
+ throw new IllegalArgumentException( "Unable to load image: " + imageName );
+ }
+
+ public JPanel createPanel()
+ {
+ JPanel jpanel1 = new JPanel();
+ FormLayout formlayout1 = new FormLayout("FILL:7DLU:NONE,RIGHT:MAX(65DLU;DEFAULT):NONE,FILL:3DLU:NONE,FILL:60DLU:NONE,FILL:DEFAULT:GROW(1.0),FILL:7DLU:NONE","CENTER:9DLU:NONE,CENTER:DEFAULT:NONE,CENTER:3DLU:NONE,CENTER:DEFAULT:NONE,CENTER:3DLU:NONE,CENTER:DEFAULT:NONE,CENTER:9DLU:NONE");
+ CellConstraints cc = new CellConstraints();
+ jpanel1.setLayout(formlayout1);
+
+ _splashFileLabel.setIcon(loadImage("images/asterix.gif"));
+ _splashFileLabel.setName("splashFileLabel");
+ _splashFileLabel.setText(Messages.getString("mutexName"));
+ jpanel1.add(_splashFileLabel,cc.xy(2,4));
+
+ _mutexNameField.setName("mutexNameField");
+ _mutexNameField.setToolTipText(Messages.getString("mutexNameTip"));
+ jpanel1.add(_mutexNameField,cc.xywh(4,4,2,1));
+
+ _singleInstanceCheck.setActionCommand("Enable splash screen");
+ _singleInstanceCheck.setName("singleInstanceCheck");
+ _singleInstanceCheck.setText(Messages.getString("enableSingleInstance"));
+ jpanel1.add(_singleInstanceCheck,cc.xywh(4,2,2,1));
+
+ _windowTitleField.setName("windowTitleField");
+ _windowTitleField.setToolTipText(Messages.getString("windowTitleTip"));
+ jpanel1.add(_windowTitleField,cc.xywh(4,6,2,1));
+
+ _splashFileLabel1.setName("splashFileLabel");
+ _splashFileLabel1.setText(Messages.getString("windowTitle"));
+ jpanel1.add(_splashFileLabel1,cc.xy(2,6));
+
+ addFillComponents(jpanel1,new int[]{ 1,2,3,4,5,6 },new int[]{ 1,2,3,4,5,6,7 });
+ return jpanel1;
+ }
+
+ /**
+ * Initializer
+ */
+ protected void initializePanel()
+ {
+ setLayout(new BorderLayout());
+ add(createPanel(), BorderLayout.CENTER);
+ }
+
+
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/form/SingleInstanceForm.jfrm b/build/windows/launcher/launch4j/src/net/sf/launch4j/form/SingleInstanceForm.jfrm
new file mode 100755
index 000000000..c9d7ce28d
Binary files /dev/null and b/build/windows/launcher/launch4j/src/net/sf/launch4j/form/SingleInstanceForm.jfrm differ
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/form/SplashForm.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/form/SplashForm.java
new file mode 100755
index 000000000..22a0ed8a3
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/form/SplashForm.java
@@ -0,0 +1,166 @@
+package net.sf.launch4j.form;
+
+import com.jgoodies.forms.layout.CellConstraints;
+import com.jgoodies.forms.layout.FormLayout;
+import java.awt.BorderLayout;
+import java.awt.Container;
+import java.awt.Dimension;
+import javax.swing.Box;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+
+public abstract class SplashForm extends JPanel
+{
+ protected final JLabel _splashFileLabel = new JLabel();
+ protected final JLabel _waitForWindowLabel = new JLabel();
+ protected final JLabel _timeoutLabel = new JLabel();
+ protected final JCheckBox _timeoutErrCheck = new JCheckBox();
+ protected final JTextField _splashFileField = new JTextField();
+ protected final JTextField _timeoutField = new JTextField();
+ protected final JButton _splashFileButton = new JButton();
+ protected final JCheckBox _splashCheck = new JCheckBox();
+ protected final JCheckBox _waitForWindowCheck = new JCheckBox();
+
+ /**
+ * Default constructor
+ */
+ public SplashForm()
+ {
+ initializePanel();
+ }
+
+ /**
+ * Adds fill components to empty cells in the first row and first column of the grid.
+ * This ensures that the grid spacing will be the same as shown in the designer.
+ * @param cols an array of column indices in the first row where fill components should be added.
+ * @param rows an array of row indices in the first column where fill components should be added.
+ */
+ void addFillComponents( Container panel, int[] cols, int[] rows )
+ {
+ Dimension filler = new Dimension(10,10);
+
+ boolean filled_cell_11 = false;
+ CellConstraints cc = new CellConstraints();
+ if ( cols.length > 0 && rows.length > 0 )
+ {
+ if ( cols[0] == 1 && rows[0] == 1 )
+ {
+ /** add a rigid area */
+ panel.add( Box.createRigidArea( filler ), cc.xy(1,1) );
+ filled_cell_11 = true;
+ }
+ }
+
+ for( int index = 0; index < cols.length; index++ )
+ {
+ if ( cols[index] == 1 && filled_cell_11 )
+ {
+ continue;
+ }
+ panel.add( Box.createRigidArea( filler ), cc.xy(cols[index],1) );
+ }
+
+ for( int index = 0; index < rows.length; index++ )
+ {
+ if ( rows[index] == 1 && filled_cell_11 )
+ {
+ continue;
+ }
+ panel.add( Box.createRigidArea( filler ), cc.xy(1,rows[index]) );
+ }
+
+ }
+
+ /**
+ * Helper method to load an image file from the CLASSPATH
+ * @param imageName the package and name of the file to load relative to the CLASSPATH
+ * @return an ImageIcon instance with the specified image file
+ * @throws IllegalArgumentException if the image resource cannot be loaded.
+ */
+ public ImageIcon loadImage( String imageName )
+ {
+ try
+ {
+ ClassLoader classloader = getClass().getClassLoader();
+ java.net.URL url = classloader.getResource( imageName );
+ if ( url != null )
+ {
+ ImageIcon icon = new ImageIcon( url );
+ return icon;
+ }
+ }
+ catch( Exception e )
+ {
+ e.printStackTrace();
+ }
+ throw new IllegalArgumentException( "Unable to load image: " + imageName );
+ }
+
+ public JPanel createPanel()
+ {
+ JPanel jpanel1 = new JPanel();
+ FormLayout formlayout1 = new FormLayout("FILL:7DLU:NONE,RIGHT:MAX(65DLU;DEFAULT):NONE,FILL:3DLU:NONE,FILL:60DLU:NONE,FILL:DEFAULT:GROW(1.0),FILL:3DLU:NONE,FILL:26PX:NONE,FILL:7DLU:NONE","CENTER:9DLU:NONE,CENTER:DEFAULT:NONE,CENTER:3DLU:NONE,CENTER:DEFAULT:NONE,CENTER:3DLU:NONE,CENTER:DEFAULT:NONE,CENTER:3DLU:NONE,CENTER:DEFAULT:NONE,CENTER:3DLU:NONE,CENTER:DEFAULT:NONE,CENTER:9DLU:NONE");
+ CellConstraints cc = new CellConstraints();
+ jpanel1.setLayout(formlayout1);
+
+ _splashFileLabel.setIcon(loadImage("images/asterix.gif"));
+ _splashFileLabel.setName("splashFileLabel");
+ _splashFileLabel.setText(Messages.getString("splashFile"));
+ jpanel1.add(_splashFileLabel,cc.xy(2,4));
+
+ _waitForWindowLabel.setName("waitForWindowLabel");
+ _waitForWindowLabel.setText(Messages.getString("waitForWindow"));
+ jpanel1.add(_waitForWindowLabel,cc.xy(2,6));
+
+ _timeoutLabel.setIcon(loadImage("images/asterix.gif"));
+ _timeoutLabel.setName("timeoutLabel");
+ _timeoutLabel.setText(Messages.getString("timeout"));
+ jpanel1.add(_timeoutLabel,cc.xy(2,8));
+
+ _timeoutErrCheck.setActionCommand("Signal error on timeout");
+ _timeoutErrCheck.setName("timeoutErrCheck");
+ _timeoutErrCheck.setText(Messages.getString("timeoutErr"));
+ _timeoutErrCheck.setToolTipText(Messages.getString("timeoutErrTip"));
+ jpanel1.add(_timeoutErrCheck,cc.xywh(4,10,2,1));
+
+ _splashFileField.setName("splashFileField");
+ _splashFileField.setToolTipText(Messages.getString("splashFileTip"));
+ jpanel1.add(_splashFileField,cc.xywh(4,4,2,1));
+
+ _timeoutField.setName("timeoutField");
+ _timeoutField.setToolTipText(Messages.getString("timeoutTip"));
+ jpanel1.add(_timeoutField,cc.xy(4,8));
+
+ _splashFileButton.setIcon(loadImage("images/open16.png"));
+ _splashFileButton.setName("splashFileButton");
+ jpanel1.add(_splashFileButton,cc.xy(7,4));
+
+ _splashCheck.setActionCommand("Enable splash screen");
+ _splashCheck.setName("splashCheck");
+ _splashCheck.setText(Messages.getString("enableSplash"));
+ jpanel1.add(_splashCheck,cc.xywh(4,2,2,1));
+
+ _waitForWindowCheck.setActionCommand("Close splash screen when an application window appears");
+ _waitForWindowCheck.setName("waitForWindowCheck");
+ _waitForWindowCheck.setText(Messages.getString("waitForWindowText"));
+ jpanel1.add(_waitForWindowCheck,cc.xywh(4,6,2,1));
+
+ addFillComponents(jpanel1,new int[]{ 1,2,3,4,5,6,7,8 },new int[]{ 1,2,3,4,5,6,7,8,9,10,11 });
+ return jpanel1;
+ }
+
+ /**
+ * Initializer
+ */
+ protected void initializePanel()
+ {
+ setLayout(new BorderLayout());
+ add(createPanel(), BorderLayout.CENTER);
+ }
+
+
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/form/SplashForm.jfrm b/build/windows/launcher/launch4j/src/net/sf/launch4j/form/SplashForm.jfrm
new file mode 100755
index 000000000..114f0e31d
Binary files /dev/null and b/build/windows/launcher/launch4j/src/net/sf/launch4j/form/SplashForm.jfrm differ
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/form/VersionInfoForm.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/form/VersionInfoForm.java
new file mode 100755
index 000000000..5a4d9440c
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/form/VersionInfoForm.java
@@ -0,0 +1,232 @@
+package net.sf.launch4j.form;
+
+import com.jeta.forms.components.separator.TitledSeparator;
+import com.jgoodies.forms.layout.CellConstraints;
+import com.jgoodies.forms.layout.FormLayout;
+import java.awt.BorderLayout;
+import java.awt.Container;
+import java.awt.Dimension;
+import javax.swing.Box;
+import javax.swing.ImageIcon;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+
+public abstract class VersionInfoForm extends JPanel
+{
+ protected final JCheckBox _versionInfoCheck = new JCheckBox();
+ protected final JLabel _fileVersionLabel = new JLabel();
+ protected final JTextField _fileVersionField = new JTextField();
+ protected final TitledSeparator _addVersionInfoSeparator = new TitledSeparator();
+ protected final JLabel _productVersionLabel = new JLabel();
+ protected final JTextField _productVersionField = new JTextField();
+ protected final JLabel _fileDescriptionLabel = new JLabel();
+ protected final JTextField _fileDescriptionField = new JTextField();
+ protected final JLabel _copyrightLabel = new JLabel();
+ protected final JTextField _copyrightField = new JTextField();
+ protected final JLabel _txtFileVersionLabel = new JLabel();
+ protected final JTextField _txtFileVersionField = new JTextField();
+ protected final JLabel _txtProductVersionLabel = new JLabel();
+ protected final JTextField _txtProductVersionField = new JTextField();
+ protected final JLabel _productNameLabel = new JLabel();
+ protected final JTextField _productNameField = new JTextField();
+ protected final JLabel _originalFilenameLabel = new JLabel();
+ protected final JTextField _originalFilenameField = new JTextField();
+ protected final JLabel _internalNameLabel = new JLabel();
+ protected final JTextField _internalNameField = new JTextField();
+ protected final JLabel _companyNameLabel = new JLabel();
+ protected final JTextField _companyNameField = new JTextField();
+
+ /**
+ * Default constructor
+ */
+ public VersionInfoForm()
+ {
+ initializePanel();
+ }
+
+ /**
+ * Adds fill components to empty cells in the first row and first column of the grid.
+ * This ensures that the grid spacing will be the same as shown in the designer.
+ * @param cols an array of column indices in the first row where fill components should be added.
+ * @param rows an array of row indices in the first column where fill components should be added.
+ */
+ void addFillComponents( Container panel, int[] cols, int[] rows )
+ {
+ Dimension filler = new Dimension(10,10);
+
+ boolean filled_cell_11 = false;
+ CellConstraints cc = new CellConstraints();
+ if ( cols.length > 0 && rows.length > 0 )
+ {
+ if ( cols[0] == 1 && rows[0] == 1 )
+ {
+ /** add a rigid area */
+ panel.add( Box.createRigidArea( filler ), cc.xy(1,1) );
+ filled_cell_11 = true;
+ }
+ }
+
+ for( int index = 0; index < cols.length; index++ )
+ {
+ if ( cols[index] == 1 && filled_cell_11 )
+ {
+ continue;
+ }
+ panel.add( Box.createRigidArea( filler ), cc.xy(cols[index],1) );
+ }
+
+ for( int index = 0; index < rows.length; index++ )
+ {
+ if ( rows[index] == 1 && filled_cell_11 )
+ {
+ continue;
+ }
+ panel.add( Box.createRigidArea( filler ), cc.xy(1,rows[index]) );
+ }
+
+ }
+
+ /**
+ * Helper method to load an image file from the CLASSPATH
+ * @param imageName the package and name of the file to load relative to the CLASSPATH
+ * @return an ImageIcon instance with the specified image file
+ * @throws IllegalArgumentException if the image resource cannot be loaded.
+ */
+ public ImageIcon loadImage( String imageName )
+ {
+ try
+ {
+ ClassLoader classloader = getClass().getClassLoader();
+ java.net.URL url = classloader.getResource( imageName );
+ if ( url != null )
+ {
+ ImageIcon icon = new ImageIcon( url );
+ return icon;
+ }
+ }
+ catch( Exception e )
+ {
+ e.printStackTrace();
+ }
+ throw new IllegalArgumentException( "Unable to load image: " + imageName );
+ }
+
+ public JPanel createPanel()
+ {
+ JPanel jpanel1 = new JPanel();
+ FormLayout formlayout1 = new FormLayout("FILL:7DLU:NONE,RIGHT:MAX(65DLU;DEFAULT):NONE,FILL:3DLU:NONE,FILL:60DLU:NONE,FILL:7DLU:NONE,RIGHT:DEFAULT:NONE,FILL:3DLU:NONE,FILL:DEFAULT:GROW(1.0),FILL:7DLU:NONE","CENTER:9DLU:NONE,CENTER:DEFAULT:NONE,CENTER:3DLU:NONE,CENTER:DEFAULT:NONE,CENTER:3DLU:NONE,CENTER:DEFAULT:NONE,CENTER:3DLU:NONE,CENTER:DEFAULT:NONE,CENTER:9DLU:NONE,CENTER:DEFAULT:NONE,CENTER:3DLU:NONE,CENTER:DEFAULT:NONE,CENTER:3DLU:NONE,CENTER:DEFAULT:NONE,CENTER:3DLU:NONE,CENTER:DEFAULT:NONE,CENTER:3DLU:NONE,CENTER:DEFAULT:NONE,CENTER:3DLU:NONE,CENTER:DEFAULT:NONE,CENTER:9DLU:NONE");
+ CellConstraints cc = new CellConstraints();
+ jpanel1.setLayout(formlayout1);
+
+ _versionInfoCheck.setActionCommand("Add version information");
+ _versionInfoCheck.setName("versionInfoCheck");
+ _versionInfoCheck.setText(Messages.getString("addVersionInfo"));
+ jpanel1.add(_versionInfoCheck,cc.xywh(4,2,5,1));
+
+ _fileVersionLabel.setIcon(loadImage("images/asterix.gif"));
+ _fileVersionLabel.setName("fileVersionLabel");
+ _fileVersionLabel.setText(Messages.getString("fileVersion"));
+ jpanel1.add(_fileVersionLabel,cc.xy(2,4));
+
+ _fileVersionField.setName("fileVersionField");
+ _fileVersionField.setToolTipText(Messages.getString("fileVersionTip"));
+ jpanel1.add(_fileVersionField,cc.xy(4,4));
+
+ _addVersionInfoSeparator.setName("addVersionInfoSeparator");
+ _addVersionInfoSeparator.setText("Additional information");
+ jpanel1.add(_addVersionInfoSeparator,cc.xywh(2,10,7,1));
+
+ _productVersionLabel.setIcon(loadImage("images/asterix.gif"));
+ _productVersionLabel.setName("productVersionLabel");
+ _productVersionLabel.setText(Messages.getString("productVersion"));
+ jpanel1.add(_productVersionLabel,cc.xy(2,12));
+
+ _productVersionField.setName("productVersionField");
+ _productVersionField.setToolTipText(Messages.getString("productVersionTip"));
+ jpanel1.add(_productVersionField,cc.xy(4,12));
+
+ _fileDescriptionLabel.setIcon(loadImage("images/asterix.gif"));
+ _fileDescriptionLabel.setName("fileDescriptionLabel");
+ _fileDescriptionLabel.setText(Messages.getString("fileDescription"));
+ jpanel1.add(_fileDescriptionLabel,cc.xy(2,6));
+
+ _fileDescriptionField.setName("fileDescriptionField");
+ _fileDescriptionField.setToolTipText(Messages.getString("fileDescriptionTip"));
+ jpanel1.add(_fileDescriptionField,cc.xywh(4,6,5,1));
+
+ _copyrightLabel.setIcon(loadImage("images/asterix.gif"));
+ _copyrightLabel.setName("copyrightLabel");
+ _copyrightLabel.setText(Messages.getString("copyright"));
+ jpanel1.add(_copyrightLabel,cc.xy(2,8));
+
+ _copyrightField.setName("copyrightField");
+ jpanel1.add(_copyrightField,cc.xywh(4,8,5,1));
+
+ _txtFileVersionLabel.setIcon(loadImage("images/asterix.gif"));
+ _txtFileVersionLabel.setName("txtFileVersionLabel");
+ _txtFileVersionLabel.setText(Messages.getString("txtFileVersion"));
+ jpanel1.add(_txtFileVersionLabel,cc.xy(6,4));
+
+ _txtFileVersionField.setName("txtFileVersionField");
+ _txtFileVersionField.setToolTipText(Messages.getString("txtFileVersionTip"));
+ jpanel1.add(_txtFileVersionField,cc.xy(8,4));
+
+ _txtProductVersionLabel.setIcon(loadImage("images/asterix.gif"));
+ _txtProductVersionLabel.setName("txtProductVersionLabel");
+ _txtProductVersionLabel.setText(Messages.getString("txtProductVersion"));
+ jpanel1.add(_txtProductVersionLabel,cc.xy(6,12));
+
+ _txtProductVersionField.setName("txtProductVersionField");
+ _txtProductVersionField.setToolTipText(Messages.getString("txtProductVersionTip"));
+ jpanel1.add(_txtProductVersionField,cc.xy(8,12));
+
+ _productNameLabel.setIcon(loadImage("images/asterix.gif"));
+ _productNameLabel.setName("productNameLabel");
+ _productNameLabel.setText(Messages.getString("productName"));
+ jpanel1.add(_productNameLabel,cc.xy(2,14));
+
+ _productNameField.setName("productNameField");
+ jpanel1.add(_productNameField,cc.xywh(4,14,5,1));
+
+ _originalFilenameLabel.setIcon(loadImage("images/asterix.gif"));
+ _originalFilenameLabel.setName("originalFilenameLabel");
+ _originalFilenameLabel.setText(Messages.getString("originalFilename"));
+ jpanel1.add(_originalFilenameLabel,cc.xy(2,20));
+
+ _originalFilenameField.setName("originalFilenameField");
+ _originalFilenameField.setToolTipText(Messages.getString("originalFilenameTip"));
+ jpanel1.add(_originalFilenameField,cc.xywh(4,20,5,1));
+
+ _internalNameLabel.setIcon(loadImage("images/asterix.gif"));
+ _internalNameLabel.setName("internalNameLabel");
+ _internalNameLabel.setText(Messages.getString("internalName"));
+ jpanel1.add(_internalNameLabel,cc.xy(2,18));
+
+ _internalNameField.setName("internalNameField");
+ _internalNameField.setToolTipText(Messages.getString("internalNameTip"));
+ jpanel1.add(_internalNameField,cc.xywh(4,18,5,1));
+
+ _companyNameLabel.setName("companyNameLabel");
+ _companyNameLabel.setText(Messages.getString("companyName"));
+ jpanel1.add(_companyNameLabel,cc.xy(2,16));
+
+ _companyNameField.setName("companyNameField");
+ jpanel1.add(_companyNameField,cc.xywh(4,16,5,1));
+
+ addFillComponents(jpanel1,new int[]{ 1,2,3,4,5,6,7,8,9 },new int[]{ 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21 });
+ return jpanel1;
+ }
+
+ /**
+ * Initializer
+ */
+ protected void initializePanel()
+ {
+ setLayout(new BorderLayout());
+ add(createPanel(), BorderLayout.CENTER);
+ }
+
+
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/form/VersionInfoForm.jfrm b/build/windows/launcher/launch4j/src/net/sf/launch4j/form/VersionInfoForm.jfrm
new file mode 100755
index 000000000..32eb136c8
Binary files /dev/null and b/build/windows/launcher/launch4j/src/net/sf/launch4j/form/VersionInfoForm.jfrm differ
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/form/messages.properties b/build/windows/launcher/launch4j/src/net/sf/launch4j/form/messages.properties
new file mode 100755
index 000000000..1be6c9584
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/form/messages.properties
@@ -0,0 +1,146 @@
+#
+# Launch4j (http://launch4j.sourceforge.net/)
+# Cross-platform Java application wrapper for creating Windows native executables.
+#
+# Copyright (c) 2004, 2007 Grzegorz Kowal
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification,
+# are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+# * Neither the name of the Launch4j nor the names of its contributors
+# may be used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+log=Log
+
+outfile=Output file:
+outfileTip=Output executable file.
+customProcName=Custom process name and XP style manifest
+stayAlive=Stay alive after launching a GUI application
+manifest=Manifest:
+manifestTip=Wrapper's manifest for User Account Control, will not enable XP styles!
+icon=Icon:
+iconTip=Application icon.
+jar=Jar:
+jarTip=Application jar.
+dontWrapJar=Dont't wrap the jar, launch only
+cmdLine=Command line args:
+cmdLineTip=Constant command line arguments passed to the application.
+options=Options:
+chdir=Change dir:
+chdirTip=Change current directory to a location relative to the executable. Empty field has no effect, . - changes directory to the exe location.
+priority=Process priority:
+normalPriority=Normal
+idlePriority=Idle
+highPriority=High
+downloadAndSupport=Java download and support
+errorTitle=Error title:
+errorTitleTip=Launch4j signals errors using a message box, you can set it's title to the application's name.
+downloadUrl=Java download URL:
+supportUrl=Support URL:
+
+new=New
+accept=Accept
+remove=Remove
+customClassPath=Custom classpath
+classPath=Classpath:
+mainClass=Main class:
+editClassPath=Edit item:
+importClassPath=Import attributes from a jar's manifest.
+
+headerType=Header type:
+gui=GUI
+console=Console
+objectFiles=Object files:
+libs=w32api:
+linkerOptions=Custom header - linker options
+
+enableSingleInstance=Allow only a single instance of the application
+mutexName=Mutex name
+mutexNameTip=Mutex name that will uniquely identify your application.
+windowTitle=Window title
+windowTitleTip=Title of the GUI application window to bring up on attempt to start a next instance.
+
+jrePath=Bundled JRE path:
+jrePathTip=Bundled JRE path relative to the executable or absolute.
+jreMin=Min JRE version:
+jreMax=Max JRE version:
+dontUsePrivateJres=Don't use private JREs
+jvmOptions=JVM options:
+jvmOptionsTip=Accepts everything you would normally pass to java/javaw launcher: assertion options, system properties and X options.
+initialHeapSize=Initial heap size:
+maxHeapSize=Max heap size:
+freeMemory=% of free memory
+jdkPreference=JDK/JRE preference:
+addVariables=Add variables:
+addVariablesTip=Add special variable or map environment variables to system properties.
+exeDirVarTip=Executable's runtime directory path.
+exeFileVarTip=Executable's runtime file path (directory and filename).
+varsAndRegistry=Variables / registry:
+envVar=Environment var:
+property=Property
+propertyTip=Map a variable to a system property.
+option=Option
+optionTip=Pass a JVM option using a variable.
+
+setVariables=Set variables:
+
+enableSplash=Enable splash screen
+splashFile=Splash file:
+splashFileTip=Splash screen file in BMP format.
+waitForWindow=Wait for window
+waitForWindowText=Close splash screen when an application window appears
+timeout=Timeout [s]:
+timeoutTip=Number of seconds after which the splash screen must close. Splash timeout may cause an error depending on splashTimeoutErr property.
+timeoutErr=Signal error on timeout
+timeoutErrTip=True signals an error on splash timeout, false closes the splash screen quietly.
+
+version=Version
+additionalInfo=Additional information
+addVersionInfo=Add version information
+fileVersion=File version:
+fileVersionTip=Version number 'x.x.x.x'
+productVersion=Product version:
+productVersionTip=Version number 'x.x.x.x'
+fileDescription=File description:
+fileDescriptionTip=File description presented to the user.
+copyright=Copyright:
+txtFileVersion=Free form:
+txtFileVersionTip=Free form file version, for example '1.20.RC1'.
+txtProductVersion=Free form:
+txtProductVersionTip=Free form product version, for example '1.20.RC1'.
+productName=Product name:
+originalFilename=Original filename:
+originalFilenameTip=Original name of the file without the path. Allows to determine whether a file has been renamed by a user.
+internalName=Internal name:
+internalNameTip=Internal name without extension, original filename or module name for example.
+companyName=Company name:
+
+addMessages=Add custom messages
+startupErr=Startup error:
+bundledJreErr=Bundled JRE error:
+jreVersionErr=JRE version error:
+jreVersionErrTip=Launch4j will append the required version number at the end of this message.
+launcherErr=Launcher error:
+instanceAlreadyExistsMsg=Inst. already exists:
+instanceAlreadyExistsMsgTip=Message displayed by single instance console applications if an instance already exists.
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/form/messages_es.properties b/build/windows/launcher/launch4j/src/net/sf/launch4j/form/messages_es.properties
new file mode 100755
index 000000000..50e2d7587
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/form/messages_es.properties
@@ -0,0 +1,118 @@
+#
+# Launch4j (http://launch4j.sourceforge.net/)
+# Cross-platform Java application wrapper for creating Windows native executables.
+#
+# Copyright (c) 2004, 2007 Grzegorz Kowal, Patricio Martínez Ros
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification,
+# are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+# * Neither the name of the Launch4j nor the names of its contributors
+# may be used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+log = Registro
+
+outfile = Fichero de salida
+outfileTip = Fichero ejecutable de salida.
+errorTitle = T\u00EDtulo de error
+errorTitleTip = Launch4j indica los errores usando una ventana de mensaje, usted puede ponerle el nombre de la aplicaci\u00F3n a esta ventana.
+customProcName = Nombre personalizado del proceso
+stayAlive = Mantener abierto despu\u00E9s de lanzar una aplicaci\u00F3n GUI
+icon = Icono
+iconTip = Icono de la aplicaci\u00F3n.
+jar = Jar
+jarTip = Jar de la aplicaci\u00F3n.
+dontWrapJar = No empaquetar el jar, s\u00F3lo lanzar
+cmdLine = Argumentos del jar
+cmdLine = Argumentos de l\u00EDnea de \u00F3rdenes pasados a la aplicaci\u00F3n.
+options = Opciones
+chdir = Cambiar al directorio
+chdirTip = Cambia el directorio actual a la localizaci\u00F3n relativa al ejecutable. Si el campo se deja vac\u00EDo, no tiene efecto, . - cambia el directorio a la localizaci\u00F3n del exe.
+headerType = Tipo de cabecera
+gui = GUI
+console = Consola
+objectFiles = Ficheros objeto
+libs = w32api
+linkerOptions = Cabecera personalizada - opciones del enlazador
+jrePath = Ruta del JRE
+jrePathTip = Ruta relativa al ejecutable del JRE.
+jreMin = Versi\u00F3n m\u00EDnima del JRE
+jreMax = Versi\u00F3n m\u00E1xima del JRE
+jvmOptions = Argumentos de la JVM
+jvmOptionsTip = Acepta cualquier argumento que normalmente se le pasar\u00EDa al lanzador java/javaw\: opciones assertion, propiedades de sistema y opciones X.
+initialHeapSize = Tama\u00F1o inicial de la pila
+maxHeapSize = Tama\u00F1o m\u00E1ximo de la pila
+freeMemory=% of free memory
+addVariables = A\u00F1adir variables
+addVariablesTip = A\u00F1adir una variable especial o mapear variables de entorno a las propiedades del sistema.
+exeDirVarTip = Ruta del directorio del ejecutable.
+exeFileVarTip = Ruta del fichero ejecutable (directorio y nombre del fichero).
+other = Otra
+otherTip = Mapear una variable de entorno a una propiedad del sistema.
+otherVarTip = Variable de entorno que mapear.
+add = A\u00F1adir
+specifyVar = Especificar variable de entorno que a\u00F1adir.
+enableSplash = Activar pantalla de bienvenida
+splashFile = Imagen
+splashFileTip = Imagen en formato BMP para la pantalla de bienvenida.
+waitForWindow = Esperar la ventana
+waitForWindowText = Cerrar la pantalla de bienvenida cuando aparezca una ventana de la aplicaci\u00F3n
+timeout = Tiempo de espera [s]
+timeoutTip = Numero de segundos despu\u00E9s de los que la pantalla de bienvenida se debe cerrar. Esta propiedad puede causar provocar un error dependiendo de la propiedad splashTimeoutErr.
+timeoutErr = Se\u00F1al de error asociada al tiempo de espera
+timeoutErrTip = Marcado (true) se\u00F1ala un error despu\u00E9s del tiempo de espera de la pantalla de bienvenida, no marcado (false) cierra la pantalla de bienvenida silenciosamente
+addVersionInfo = A\u00F1ade informaci\u00F3n sobre la versi\u00F3n
+fileVersion = Versi\u00F3n del fichero
+fileVersionTip = N\u00FAmero de versi\u00F3n 'x.x.x.x'
+additionalInfo = Informaci\u00F3n adicional
+productVersion = Versi\u00F3n del producto
+productVersionTip = N\u00FAmero de versi\u00F3n 'x.x.x.x'
+fileDescription = Descripci\u00F3n del fichero
+fileDescriptionTip = Descripci\u00F3n del fichero que se le muestra al usuario.
+copyright = Copyright
+txtFileVersion = Forma libre
+txtFileVersionTip = Forma libre de versi\u00F3n, por ejemplo '1.20.RC1'.
+txtProductVersion = Forma libre
+txtProductVersionTip = Forma libre del producto, por ejemplo '1.20.RC1'.
+productName = Nombre del producto
+originalFilename = Nombre original del fichero
+originalFilenameTip = Nombre original del fichero sin la ruta. Permite determinar si un fichero ha sido renombrado por un usuario.
+internalName = Nombre interno
+internalNameTip = Nombre interno sin extensi\u00F3n, el nombre original del fichero o el m\u00F3dulo, por ejemplo.
+companyName = Nombre de la organizaci\u00F3n
+
+addMessages=Add custom messages
+startupErr=Startup error:
+bundledJreErr=Bundled JRE error:
+jreVersionErr=JRE version error:
+jreVersionErrTip=Launch4j will append the required version number at the end of this message.
+launcherErr=Launcher error:
+instanceAlreadyExistsMsg=Inst. already exists:
+instanceAlreadyExistsMsgTip=Message displayed by single instance console applications if an instance already exists.
+
+enableSingleInstance=Allow only a single instance of the application
+mutexName=Mutex name
+mutexNameTip=Mutex name that will uniquely identify your application.
+windowTitle=Window title
+windowTitleTip=Title of the application window to bring up on attempt to start a next instance.
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/AbstractAcceptListener.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/AbstractAcceptListener.java
new file mode 100755
index 000000000..5265e6436
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/AbstractAcceptListener.java
@@ -0,0 +1,75 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on May 1, 2006
+ */
+package net.sf.launch4j.formimpl;
+
+import java.awt.Color;
+import java.awt.event.ActionListener;
+
+import javax.swing.JTextField;
+
+import net.sf.launch4j.binding.Binding;
+
+/**
+ * @author Copyright (C) 2006 Grzegorz Kowal
+ */
+public abstract class AbstractAcceptListener implements ActionListener {
+ final JTextField _field;
+
+ public AbstractAcceptListener(JTextField f, boolean listen) {
+ _field = f;
+ if (listen) {
+ _field.addActionListener(this);
+ }
+ }
+
+ protected String getText() {
+ return _field.getText();
+ }
+
+ protected void clear() {
+ _field.setText("");
+ _field.requestFocusInWindow();
+ }
+
+ protected void signalViolation(String msg) {
+ final Color bg = _field.getBackground();
+ _field.setBackground(Binding.INVALID_COLOR);
+ MainFrame.getInstance().warn(msg);
+ _field.setBackground(bg);
+ _field.requestFocusInWindow();
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/BasicFormImpl.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/BasicFormImpl.java
new file mode 100755
index 000000000..01ebe8adf
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/BasicFormImpl.java
@@ -0,0 +1,101 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on May 1, 2006
+ */
+package net.sf.launch4j.formimpl;
+
+import javax.swing.JFileChooser;
+import javax.swing.JRadioButton;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+import net.sf.launch4j.FileChooserFilter;
+import net.sf.launch4j.binding.Bindings;
+import net.sf.launch4j.config.Config;
+import net.sf.launch4j.form.BasicForm;
+
+/**
+ * @author Copyright (C) 2006 Grzegorz Kowal
+ */
+public class BasicFormImpl extends BasicForm {
+
+ public BasicFormImpl(Bindings bindings, JFileChooser fc) {
+ bindings.add("outfile", _outfileField)
+ .add("dontWrapJar", _dontWrapJarCheck)
+ .add("jar", _jarField)
+ .add("manifest", _manifestField)
+ .add("icon", _iconField)
+ .add("cmdLine", _cmdLineField)
+ .add("errTitle", _errorTitleField)
+ .add("downloadUrl", _downloadUrlField, Config.DOWNLOAD_URL)
+ .add("supportUrl", _supportUrlField)
+ .add("chdir", _chdirField)
+ .add("priorityIndex", new JRadioButton[] { _normalPriorityRadio,
+ _idlePriorityRadio,
+ _highPriorityRadio })
+ .add("customProcName", _customProcNameCheck)
+ .add("stayAlive", _stayAliveCheck);
+
+ _dontWrapJarCheck.addChangeListener(new DontWrapJarChangeListener());
+
+ _outfileButton.addActionListener(new BrowseActionListener(true, fc,
+ new FileChooserFilter("Windows executables (.exe)", ".exe"),
+ _outfileField));
+ _jarButton.addActionListener(new BrowseActionListener(false, fc,
+ new FileChooserFilter("Jar files", ".jar"), _jarField));
+ _manifestButton.addActionListener(new BrowseActionListener(false, fc,
+ new FileChooserFilter("Manifest files (.manifest)", ".manifest"),
+ _manifestField));
+ _iconButton.addActionListener(new BrowseActionListener(false, fc,
+ new FileChooserFilter("Icon files (.ico)", ".ico"), _iconField));
+ }
+
+ private class DontWrapJarChangeListener implements ChangeListener {
+
+ public void stateChanged(ChangeEvent e) {
+ boolean dontWrap = _dontWrapJarCheck.isSelected();
+ if (dontWrap) {
+ _jarLabel.setIcon(loadImage("images/asterix-o.gif"));
+ _jarLabel.setText(Messages.getString("jarPath"));
+ _jarField.setToolTipText(Messages.getString("jarPathTip"));
+ } else {
+ _jarLabel.setIcon(loadImage("images/asterix.gif"));
+ _jarLabel.setText(Messages.getString("jar"));
+ _jarField.setToolTipText(Messages.getString("jarTip"));
+ }
+ _jarButton.setEnabled(!dontWrap);
+ }
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/BrowseActionListener.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/BrowseActionListener.java
new file mode 100755
index 000000000..89a5017ee
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/BrowseActionListener.java
@@ -0,0 +1,79 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on May 1, 2006
+ */
+package net.sf.launch4j.formimpl;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.File;
+
+import javax.swing.JFileChooser;
+import javax.swing.JTextField;
+
+import net.sf.launch4j.FileChooserFilter;
+
+/**
+ * @author Copyright (C) 2006 Grzegorz Kowal
+ */
+public class BrowseActionListener implements ActionListener {
+ private final boolean _save;
+ private final JFileChooser _fileChooser;
+ private final FileChooserFilter _filter;
+ private final JTextField _field;
+
+ public BrowseActionListener(boolean save, JFileChooser fileChooser,
+ FileChooserFilter filter, JTextField field) {
+ _save = save;
+ _fileChooser = fileChooser;
+ _filter = filter;
+ _field = field;
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ if (!_field.isEnabled()) {
+ return;
+ }
+ _fileChooser.setFileFilter(_filter);
+ _fileChooser.setSelectedFile(new File(""));
+ int result = _save
+ ? _fileChooser.showSaveDialog(MainFrame.getInstance())
+ : _fileChooser.showOpenDialog(MainFrame.getInstance());
+ if (result == JFileChooser.APPROVE_OPTION) {
+ _field.setText(_fileChooser.getSelectedFile().getPath());
+ }
+ _fileChooser.removeChoosableFileFilter(_filter);
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/ClassPathFormImpl.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/ClassPathFormImpl.java
new file mode 100755
index 000000000..65d82096e
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/ClassPathFormImpl.java
@@ -0,0 +1,222 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on May 1, 2006
+ */
+package net.sf.launch4j.formimpl;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.File;
+import java.io.IOException;
+import java.util.jar.Attributes;
+import java.util.jar.JarFile;
+
+import javax.swing.DefaultListModel;
+import javax.swing.JFileChooser;
+import javax.swing.JTextField;
+import javax.swing.ListSelectionModel;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+
+import net.sf.launch4j.FileChooserFilter;
+import net.sf.launch4j.binding.Bindings;
+import net.sf.launch4j.binding.Validator;
+import net.sf.launch4j.config.ClassPath;
+import net.sf.launch4j.form.ClassPathForm;
+
+/**
+ * @author Copyright (C) 2006 Grzegorz Kowal
+ */
+public class ClassPathFormImpl extends ClassPathForm {
+ private final JFileChooser _fileChooser;
+ private final FileChooserFilter _filter
+ = new FileChooserFilter("Executable jar", ".jar");
+
+ public ClassPathFormImpl(Bindings bindings, JFileChooser fc) {
+ bindings.addOptComponent("classPath", ClassPath.class, _classpathCheck)
+ .add("classPath.mainClass", _mainclassField)
+ .add("classPath.paths", _classpathList);
+ _fileChooser = fc;
+
+ ClasspathCheckListener cpl = new ClasspathCheckListener();
+ _classpathCheck.addChangeListener(cpl);
+ cpl.stateChanged(null);
+
+ _classpathList.setModel(new DefaultListModel());
+ _classpathList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
+ _classpathList.addListSelectionListener(new ClasspathSelectionListener());
+
+ _newClasspathButton.addActionListener(new NewClasspathListener());
+ _acceptClasspathButton.addActionListener(
+ new AcceptClasspathListener(_classpathField));
+ _removeClasspathButton.addActionListener(new RemoveClasspathListener());
+ _importClasspathButton.addActionListener(new ImportClasspathListener());
+ _classpathUpButton.addActionListener(new MoveUpListener());
+ _classpathDownButton.addActionListener(new MoveDownListener());
+ }
+
+ private class ClasspathCheckListener implements ChangeListener {
+ public void stateChanged(ChangeEvent e) {
+ boolean on = _classpathCheck.isSelected();
+ _importClasspathButton.setEnabled(on);
+ _classpathUpButton.setEnabled(on);
+ _classpathDownButton.setEnabled(on);
+ _classpathField.setEnabled(on);
+ _newClasspathButton.setEnabled(on);
+ _acceptClasspathButton.setEnabled(on);
+ _removeClasspathButton.setEnabled(on);
+ }
+ }
+
+ private class NewClasspathListener implements ActionListener {
+ public void actionPerformed(ActionEvent e) {
+ _classpathList.clearSelection();
+ _classpathField.setText("");
+ _classpathField.requestFocusInWindow();
+ }
+ }
+
+ private class AcceptClasspathListener extends AbstractAcceptListener {
+ public AcceptClasspathListener(JTextField f) {
+ super(f, true);
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ String cp = getText();
+ if (Validator.isEmpty(cp)) {
+ signalViolation(Messages.getString("specifyClassPath"));
+ return;
+ }
+ DefaultListModel model = (DefaultListModel) _classpathList.getModel();
+ if (_classpathList.isSelectionEmpty()) {
+ model.addElement(cp);
+ clear();
+ } else {
+ model.setElementAt(cp, _classpathList.getSelectedIndex());
+ }
+ }
+ }
+
+ private class ClasspathSelectionListener implements ListSelectionListener {
+ public void valueChanged(ListSelectionEvent e) {
+ if (e.getValueIsAdjusting()) {
+ return;
+ }
+ if (_classpathList.isSelectionEmpty()) {
+ _classpathField.setText("");
+ } else {
+ _classpathField.setText((String) _classpathList.getSelectedValue());
+ }
+ _classpathField.requestFocusInWindow();
+ }
+ }
+
+ private class RemoveClasspathListener implements ActionListener {
+ public void actionPerformed(ActionEvent e) {
+ if (_classpathList.isSelectionEmpty()
+ || !MainFrame.getInstance().confirm(
+ Messages.getString("confirmClassPathRemoval"))) {
+ return;
+ }
+ DefaultListModel model = (DefaultListModel) _classpathList.getModel();
+ while (!_classpathList.isSelectionEmpty()) {
+ model.remove(_classpathList.getSelectedIndex());
+ }
+ }
+ }
+
+ private class MoveUpListener implements ActionListener {
+ public void actionPerformed(ActionEvent e) {
+ int x = _classpathList.getSelectedIndex();
+ if (x < 1) {
+ return;
+ }
+ DefaultListModel model = (DefaultListModel) _classpathList.getModel();
+ Object o = model.get(x - 1);
+ model.set(x - 1, model.get(x));
+ model.set(x, o);
+ _classpathList.setSelectedIndex(x - 1);
+ }
+ }
+
+ private class MoveDownListener implements ActionListener {
+ public void actionPerformed(ActionEvent e) {
+ DefaultListModel model = (DefaultListModel) _classpathList.getModel();
+ int x = _classpathList.getSelectedIndex();
+ if (x == -1 || x >= model.getSize() - 1) {
+ return;
+ }
+ Object o = model.get(x + 1);
+ model.set(x + 1, model.get(x));
+ model.set(x, o);
+ _classpathList.setSelectedIndex(x + 1);
+ }
+ }
+
+ private class ImportClasspathListener implements ActionListener {
+ public void actionPerformed(ActionEvent e) {
+ try {
+ _fileChooser.setFileFilter(_filter);
+ _fileChooser.setSelectedFile(new File(""));
+ if (_fileChooser.showOpenDialog(MainFrame.getInstance())
+ == JFileChooser.APPROVE_OPTION) {
+ JarFile jar = new JarFile(_fileChooser.getSelectedFile());
+ if (jar.getManifest() == null) {
+ jar.close();
+ MainFrame.getInstance().info(Messages.getString("noManifest"));
+ return;
+ }
+ Attributes attr = jar.getManifest().getMainAttributes();
+ String mainClass = (String) attr.getValue("Main-Class");
+ String classPath = (String) attr.getValue("Class-Path");
+ jar.close();
+ _mainclassField.setText(mainClass != null ? mainClass : "");
+ DefaultListModel model = new DefaultListModel();
+ if (classPath != null) {
+ String[] paths = classPath.split(" ");
+ for (int i = 0; i < paths.length; i++) {
+ model.addElement(paths[i]);
+ }
+ }
+ _classpathList.setModel(model);
+ }
+ } catch (IOException ex) {
+ MainFrame.getInstance().warn(ex.getMessage());
+ }
+ }
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/ConfigFormImpl.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/ConfigFormImpl.java
new file mode 100755
index 000000000..d29720642
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/ConfigFormImpl.java
@@ -0,0 +1,100 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on May 10, 2005
+ */
+package net.sf.launch4j.formimpl;
+
+import javax.swing.BorderFactory;
+import javax.swing.JFileChooser;
+import javax.swing.JTextArea;
+
+import net.sf.launch4j.binding.Binding;
+import net.sf.launch4j.binding.Bindings;
+import net.sf.launch4j.binding.IValidatable;
+import net.sf.launch4j.form.ConfigForm;
+
+/**
+ * @author Copyright (C) 2005 Grzegorz Kowal
+ */
+public class ConfigFormImpl extends ConfigForm {
+ private final Bindings _bindings = new Bindings();
+ private final JFileChooser _fileChooser = new FileChooser(ConfigFormImpl.class);
+
+ public ConfigFormImpl() {
+ _tab.setBorder(BorderFactory.createMatteBorder(0, -1, -1, -1, getBackground()));
+ _tab.addTab(Messages.getString("tab.basic"),
+ new BasicFormImpl(_bindings, _fileChooser));
+ _tab.addTab(Messages.getString("tab.classpath"),
+ new ClassPathFormImpl(_bindings, _fileChooser));
+ _tab.addTab(Messages.getString("tab.header"),
+ new HeaderFormImpl(_bindings));
+ _tab.addTab(Messages.getString("tab.singleInstance"),
+ new SingleInstanceFormImpl(_bindings));
+ _tab.addTab(Messages.getString("tab.jre"),
+ new JreFormImpl(_bindings, _fileChooser));
+ _tab.addTab(Messages.getString("tab.envVars"),
+ new EnvironmentVarsFormImpl(_bindings));
+ _tab.addTab(Messages.getString("tab.splash"),
+ new SplashFormImpl(_bindings, _fileChooser));
+ _tab.addTab(Messages.getString("tab.version"),
+ new VersionInfoFormImpl(_bindings, _fileChooser));
+ _tab.addTab(Messages.getString("tab.messages"),
+ new MessagesFormImpl(_bindings));
+ }
+
+ public void clear(IValidatable bean) {
+ _bindings.clear(bean);
+ }
+
+ public void put(IValidatable bean) {
+ _bindings.put(bean);
+ }
+
+ public void get(IValidatable bean) {
+ _bindings.get(bean);
+ }
+
+ public boolean isModified() {
+ return _bindings.isModified();
+ }
+
+ public JTextArea getLogTextArea() {
+ return _logTextArea;
+ }
+
+ public Binding getBinding(String property) {
+ return _bindings.getBinding(property);
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/EnvironmentVarsFormImpl.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/EnvironmentVarsFormImpl.java
new file mode 100755
index 000000000..2f325fe3c
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/EnvironmentVarsFormImpl.java
@@ -0,0 +1,50 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on Jun 10, 2006
+ */
+package net.sf.launch4j.formimpl;
+
+import net.sf.launch4j.binding.Bindings;
+import net.sf.launch4j.form.EnvironmentVarsForm;
+
+/**
+ * @author Copyright (C) 2006 Grzegorz Kowal
+ */
+public class EnvironmentVarsFormImpl extends EnvironmentVarsForm {
+
+ public EnvironmentVarsFormImpl(Bindings bindings) {
+ bindings.add("variables", _envVarsTextArea);
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/FileChooser.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/FileChooser.java
new file mode 100755
index 000000000..c1b984e58
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/FileChooser.java
@@ -0,0 +1,65 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on Jul 19, 2006
+ */
+package net.sf.launch4j.formimpl;
+
+import java.io.File;
+import java.util.prefs.Preferences;
+
+import javax.swing.JFileChooser;
+
+/**
+ * @author Copyright (C) 2006 Grzegorz Kowal
+ */
+public class FileChooser extends JFileChooser {
+ private final Preferences _prefs;
+ private final String _key;
+
+ public FileChooser(Class clazz) {
+ _prefs = Preferences.userNodeForPackage(clazz);
+ _key = "currentDir-"
+ + clazz.getName().substring(clazz.getName().lastIndexOf('.') + 1);
+ String path = _prefs.get(_key, null);
+ if (path != null) {
+ setCurrentDirectory(new File(path));
+ }
+ }
+
+ public void approveSelection() {
+ _prefs.put(_key, getCurrentDirectory().getPath());
+ super.approveSelection();
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/GlassPane.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/GlassPane.java
new file mode 100755
index 000000000..c1b1d8dd4
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/GlassPane.java
@@ -0,0 +1,67 @@
+package net.sf.launch4j.formimpl;
+
+import java.awt.AWTEvent;
+import java.awt.Component;
+import java.awt.Cursor;
+import java.awt.Toolkit;
+import java.awt.Window;
+import java.awt.event.AWTEventListener;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseAdapter;
+
+import javax.swing.JComponent;
+import javax.swing.SwingUtilities;
+
+/**
+ * This is the glass pane class that intercepts screen interactions during
+ * system busy states.
+ *
+ * Based on JavaWorld article by Yexin Chen.
+ */
+public class GlassPane extends JComponent implements AWTEventListener {
+ private final Window _window;
+
+ public GlassPane(Window w) {
+ _window = w;
+ addMouseListener(new MouseAdapter() {});
+ addKeyListener(new KeyAdapter() {});
+ setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
+ }
+
+ /**
+ * Receives all key events in the AWT and processes the ones that originated
+ * from the current window with the glass pane.
+ *
+ * @param event
+ * the AWTEvent that was fired
+ */
+ public void eventDispatched(AWTEvent event) {
+ Object source = event.getSource();
+ if (event instanceof KeyEvent
+ && source instanceof Component) {
+ /*
+ * If the event originated from the window w/glass pane,
+ * consume the event.
+ */
+ if ((SwingUtilities.windowForComponent((Component) source) == _window)) {
+ ((KeyEvent) event).consume();
+ }
+ }
+ }
+
+ /**
+ * Sets the glass pane as visible or invisible. The mouse cursor will be set
+ * accordingly.
+ */
+ public void setVisible(boolean visible) {
+ if (visible) {
+ // Start receiving all events and consume them if necessary
+ Toolkit.getDefaultToolkit().addAWTEventListener(this, AWTEvent.KEY_EVENT_MASK);
+ } else {
+ // Stop receiving all events
+ Toolkit.getDefaultToolkit().removeAWTEventListener(this);
+ }
+ super.setVisible(visible);
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/HeaderFormImpl.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/HeaderFormImpl.java
new file mode 100755
index 000000000..accfaa9de
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/HeaderFormImpl.java
@@ -0,0 +1,102 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on May 1, 2006
+ */
+package net.sf.launch4j.formimpl;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.JRadioButton;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+import net.sf.launch4j.binding.Binding;
+import net.sf.launch4j.binding.Bindings;
+import net.sf.launch4j.config.Config;
+import net.sf.launch4j.config.ConfigPersister;
+import net.sf.launch4j.form.HeaderForm;
+
+/**
+ * @author Copyright (C) 2006 Grzegorz Kowal
+ */
+public class HeaderFormImpl extends HeaderForm {
+ private final Bindings _bindings;
+
+ public HeaderFormImpl(Bindings bindings) {
+ _bindings = bindings;
+ _bindings.add("headerTypeIndex", new JRadioButton[] { _guiHeaderRadio,
+ _consoleHeaderRadio })
+ .add("headerObjects", "customHeaderObjects", _headerObjectsCheck,
+ _headerObjectsTextArea)
+ .add("libs", "customLibs", _libsCheck, _libsTextArea);
+
+ _guiHeaderRadio.addChangeListener(new HeaderTypeChangeListener());
+ _headerObjectsCheck.addActionListener(new HeaderObjectsActionListener());
+ _libsCheck.addActionListener(new LibsActionListener());
+ }
+
+ private class HeaderTypeChangeListener implements ChangeListener {
+ public void stateChanged(ChangeEvent e) {
+ Config c = ConfigPersister.getInstance().getConfig();
+ c.setHeaderType(_guiHeaderRadio.isSelected() ? Config.GUI_HEADER
+ : Config.CONSOLE_HEADER);
+ if (!_headerObjectsCheck.isSelected()) {
+ Binding b = _bindings.getBinding("headerObjects");
+ b.put(c);
+ }
+ }
+ }
+
+ private class HeaderObjectsActionListener implements ActionListener {
+ public void actionPerformed(ActionEvent e) {
+ if (!_headerObjectsCheck.isSelected()) {
+ ConfigPersister.getInstance().getConfig().setHeaderObjects(null);
+ Binding b = _bindings.getBinding("headerObjects");
+ b.put(ConfigPersister.getInstance().getConfig());
+ }
+ }
+ }
+
+ private class LibsActionListener implements ActionListener {
+ public void actionPerformed(ActionEvent e) {
+ if (!_libsCheck.isSelected()) {
+ ConfigPersister.getInstance().getConfig().setLibs(null);
+ Binding b = _bindings.getBinding("libs");
+ b.put(ConfigPersister.getInstance().getConfig());
+ }
+ }
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/JreFormImpl.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/JreFormImpl.java
new file mode 100755
index 000000000..48a2f18e8
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/JreFormImpl.java
@@ -0,0 +1,166 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on May 1, 2006
+ */
+package net.sf.launch4j.formimpl;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.JFileChooser;
+import javax.swing.JTextField;
+
+import net.sf.launch4j.binding.Bindings;
+import net.sf.launch4j.binding.Validator;
+import net.sf.launch4j.form.JreForm;
+import net.sf.launch4j.config.Jre;
+
+/**
+ * @author Copyright (C) 2006 Grzegorz Kowal
+ */
+public class JreFormImpl extends JreForm {
+
+ public JreFormImpl(Bindings bindings, JFileChooser fc) {
+ _jdkPreferenceCombo.setModel(new DefaultComboBoxModel(new String[] {
+ Messages.getString("jdkPreference.jre.only"),
+ Messages.getString("jdkPreference.prefer.jre"),
+ Messages.getString("jdkPreference.prefer.jdk"),
+ Messages.getString("jdkPreference.jdk.only")}));
+ bindings.add("jre.path", _jrePathField)
+ .add("jre.minVersion", _jreMinField)
+ .add("jre.maxVersion", _jreMaxField)
+ .add("jre.jdkPreferenceIndex", _jdkPreferenceCombo,
+ Jre.DEFAULT_JDK_PREFERENCE_INDEX)
+ .add("jre.initialHeapSize", _initialHeapSizeField)
+ .add("jre.initialHeapPercent", _initialHeapPercentField)
+ .add("jre.maxHeapSize", _maxHeapSizeField)
+ .add("jre.maxHeapPercent", _maxHeapPercentField)
+ .add("jre.options", _jvmOptionsTextArea);
+
+ _varCombo.setModel(new DefaultComboBoxModel(new String[] {
+ "EXEDIR", "EXEFILE", "PWD", "OLDPWD",
+ "HKEY_CLASSES_ROOT", "HKEY_CURRENT_USER", "HKEY_LOCAL_MACHINE",
+ "HKEY_USERS", "HKEY_CURRENT_CONFIG" }));
+
+ _varCombo.addActionListener(new VarComboActionListener());
+ _varCombo.setSelectedIndex(0);
+
+ _propertyButton.addActionListener(new PropertyActionListener());
+ _optionButton.addActionListener(new OptionActionListener());
+
+ _envPropertyButton.addActionListener(new EnvPropertyActionListener(_envVarField));
+ _envOptionButton.addActionListener(new EnvOptionActionListener(_envVarField));
+ }
+
+ private class VarComboActionListener implements ActionListener {
+ public void actionPerformed(ActionEvent e) {
+ _optionButton.setEnabled(((String) _varCombo.getSelectedItem())
+ .startsWith("HKEY_"));
+ }
+ }
+
+ private class PropertyActionListener implements ActionListener {
+ public void actionPerformed(ActionEvent e) {
+ final int pos = _jvmOptionsTextArea.getCaretPosition();
+ final String var = (String) _varCombo.getSelectedItem();
+ if (var.startsWith("HKEY_")) {
+ _jvmOptionsTextArea.insert("-Dreg.key=\"%"
+ + var + "\\\\...%\"\n", pos);
+ } else {
+ _jvmOptionsTextArea.insert("-Dlaunch4j." + var.toLowerCase()
+ + "=\"%" + var + "%\"\n", pos);
+ }
+ }
+ }
+
+ private class OptionActionListener implements ActionListener {
+ public void actionPerformed(ActionEvent e) {
+ final int pos = _jvmOptionsTextArea.getCaretPosition();
+ final String var = (String) _varCombo.getSelectedItem();
+ if (var.startsWith("HKEY_")) {
+ _jvmOptionsTextArea.insert("%" + var + "\\\\...%\n", pos);
+ } else {
+ _jvmOptionsTextArea.insert("%" + var + "%\n", pos);
+ }
+ }
+ }
+
+ private abstract class EnvActionListener extends AbstractAcceptListener {
+ public EnvActionListener(JTextField f, boolean listen) {
+ super(f, listen);
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ final int pos = _jvmOptionsTextArea.getCaretPosition();
+ final String var = getText()
+ .replaceAll("\"", "")
+ .replaceAll("%", "");
+ if (Validator.isEmpty(var)) {
+ signalViolation(Messages.getString("specifyVar"));
+ return;
+ }
+ add(var, pos);
+ clear();
+ }
+
+ protected abstract void add(String var, int pos);
+ }
+
+ private class EnvPropertyActionListener extends EnvActionListener {
+ public EnvPropertyActionListener(JTextField f) {
+ super(f, true);
+ }
+
+ protected void add(String var, int pos) {
+ final String prop = var
+ .replaceAll(" ", ".")
+ .replaceAll("_", ".")
+ .toLowerCase();
+ _jvmOptionsTextArea.insert("-Denv." + prop + "=\"%" + var
+ + "%\"\n", pos);
+ }
+ }
+
+ private class EnvOptionActionListener extends EnvActionListener {
+ public EnvOptionActionListener(JTextField f) {
+ super(f, false);
+ }
+
+ protected void add(String var, int pos) {
+ _jvmOptionsTextArea.insert("%" + var + "%\n", pos);
+ }
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/MainFrame.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/MainFrame.java
new file mode 100755
index 000000000..4a2cc8715
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/MainFrame.java
@@ -0,0 +1,358 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on 2005-05-09
+ */
+package net.sf.launch4j.formimpl;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.Toolkit;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.io.File;
+
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JFileChooser;
+import javax.swing.JFrame;
+import javax.swing.JOptionPane;
+import javax.swing.JToolBar;
+import javax.swing.UIManager;
+
+import com.jgoodies.looks.Options;
+import com.jgoodies.looks.plastic.PlasticXPLookAndFeel;
+
+import foxtrot.Task;
+import foxtrot.Worker;
+
+import net.sf.launch4j.Builder;
+import net.sf.launch4j.BuilderException;
+import net.sf.launch4j.ExecException;
+import net.sf.launch4j.FileChooserFilter;
+import net.sf.launch4j.Log;
+import net.sf.launch4j.Main;
+import net.sf.launch4j.Util;
+import net.sf.launch4j.binding.Binding;
+import net.sf.launch4j.binding.BindingException;
+import net.sf.launch4j.binding.InvariantViolationException;
+import net.sf.launch4j.config.Config;
+import net.sf.launch4j.config.ConfigPersister;
+import net.sf.launch4j.config.ConfigPersisterException;
+
+/**
+ * @author Copyright (C) 2005 Grzegorz Kowal
+ */
+public class MainFrame extends JFrame {
+ private static MainFrame _instance;
+
+ private final JToolBar _toolBar;
+ private final JButton _runButton;
+ private final ConfigFormImpl _configForm;
+ private final JFileChooser _fileChooser = new FileChooser(MainFrame.class);
+ private File _outfile;
+ private boolean _saved = false;
+
+ public static void createInstance() {
+ try {
+ Toolkit.getDefaultToolkit().setDynamicLayout(true);
+ System.setProperty("sun.awt.noerasebackground","true");
+
+ // JGoodies
+ Options.setDefaultIconSize(new Dimension(16, 16)); // menu icons
+ Options.setUseNarrowButtons(false);
+ Options.setPopupDropShadowEnabled(true);
+
+ UIManager.setLookAndFeel(new PlasticXPLookAndFeel());
+ _instance = new MainFrame();
+ } catch (Exception e) {
+ System.err.println(e);
+ }
+ }
+
+ public static MainFrame getInstance() {
+ return _instance;
+ }
+
+ public MainFrame() {
+ showConfigName(null);
+ setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
+ addWindowListener(new MainFrameListener());
+ setGlassPane(new GlassPane(this));
+ _fileChooser.setFileFilter(new FileChooserFilter(
+ Messages.getString("MainFrame.config.files"),
+ new String[] {".xml", ".cfg"}));
+
+ _toolBar = new JToolBar();
+ _toolBar.setFloatable(false);
+ _toolBar.setRollover(true);
+ addButton("images/new.png", Messages.getString("MainFrame.new.config"),
+ new NewActionListener());
+ addButton("images/open.png", Messages.getString("MainFrame.open.config"),
+ new OpenActionListener());
+ addButton("images/save.png", Messages.getString("MainFrame.save.config"),
+ new SaveActionListener());
+ _toolBar.addSeparator();
+ addButton("images/build.png", Messages.getString("MainFrame.build.wrapper"),
+ new BuildActionListener());
+ _runButton = addButton("images/run.png",
+ Messages.getString("MainFrame.test.wrapper"),
+ new RunActionListener());
+ setRunEnabled(false);
+ _toolBar.addSeparator();
+ addButton("images/info.png", Messages.getString("MainFrame.about.launch4j"),
+ new AboutActionListener());
+
+ _configForm = new ConfigFormImpl();
+ getContentPane().setLayout(new BorderLayout());
+ getContentPane().add(_toolBar, BorderLayout.NORTH);
+ getContentPane().add(_configForm, BorderLayout.CENTER);
+ pack();
+ Dimension scr = Toolkit.getDefaultToolkit().getScreenSize();
+ Dimension fr = getSize();
+ fr.width += 25;
+ fr.height += 100;
+ setBounds((scr.width - fr.width) / 2, (scr.height - fr.height) / 2,
+ fr.width, fr.height);
+ setVisible(true);
+ }
+
+ private JButton addButton(String iconPath, String tooltip, ActionListener l) {
+ ImageIcon icon = new ImageIcon(MainFrame.class.getClassLoader()
+ .getResource(iconPath));
+ JButton b = new JButton(icon);
+ b.setToolTipText(tooltip);
+ b.addActionListener(l);
+ _toolBar.add(b);
+ return b;
+ }
+
+ public void info(String text) {
+ JOptionPane.showMessageDialog(this,
+ text,
+ Main.getName(),
+ JOptionPane.INFORMATION_MESSAGE);
+ }
+
+ public void warn(String text) {
+ JOptionPane.showMessageDialog(this,
+ text,
+ Main.getName(),
+ JOptionPane.WARNING_MESSAGE);
+ }
+
+ public void warn(InvariantViolationException e) {
+ Binding b = e.getBinding();
+ if (b != null) {
+ b.markInvalid();
+ }
+ warn(e.getMessage());
+ if (b != null) {
+ e.getBinding().markValid();
+ }
+ }
+
+ public boolean confirm(String text) {
+ return JOptionPane.showConfirmDialog(MainFrame.this,
+ text,
+ Messages.getString("MainFrame.confirm"),
+ JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION;
+ }
+
+ private boolean isModified() {
+ return (!_configForm.isModified())
+ || confirm(Messages.getString("MainFrame.discard.changes"));
+ }
+
+ private boolean save() {
+ // XXX
+ try {
+ _configForm.get(ConfigPersister.getInstance().getConfig());
+ if (_fileChooser.showSaveDialog(MainFrame.this) == JOptionPane.YES_OPTION) {
+ File f = _fileChooser.getSelectedFile();
+ if (!f.getPath().endsWith(".xml")) {
+ f = new File(f.getPath() + ".xml");
+ }
+ ConfigPersister.getInstance().save(f);
+ _saved = true;
+ showConfigName(f);
+ return true;
+ }
+ return false;
+ } catch (InvariantViolationException ex) {
+ warn(ex);
+ return false;
+ } catch (BindingException ex) {
+ warn(ex.getMessage());
+ return false;
+ } catch (ConfigPersisterException ex) {
+ warn(ex.getMessage());
+ return false;
+ }
+ }
+
+ private void showConfigName(File config) {
+ setTitle(Main.getName() + " - " + (config != null ? config.getName()
+ : Messages.getString("MainFrame.untitled")));
+ }
+
+ private void setRunEnabled(boolean enabled) {
+ if (!enabled) {
+ _outfile = null;
+ }
+ _runButton.setEnabled(enabled);
+ }
+
+ private void clearConfig() {
+ ConfigPersister.getInstance().createBlank();
+ _configForm.clear(ConfigPersister.getInstance().getConfig());
+ }
+
+ private class MainFrameListener extends WindowAdapter {
+ public void windowOpened(WindowEvent e) {
+ clearConfig();
+ }
+
+ public void windowClosing(WindowEvent e) {
+ if (isModified()) {
+ System.exit(0);
+ }
+ }
+ }
+
+ private class NewActionListener implements ActionListener {
+ public void actionPerformed(ActionEvent e) {
+ if (isModified()) {
+ clearConfig();
+ }
+ _saved = false;
+ showConfigName(null);
+ setRunEnabled(false);
+ }
+ }
+
+ private class OpenActionListener implements ActionListener {
+ public void actionPerformed(ActionEvent e) {
+ try {
+ if (isModified() && _fileChooser.showOpenDialog(MainFrame.this)
+ == JOptionPane.YES_OPTION) {
+ final File f = _fileChooser.getSelectedFile();
+ if (f.getPath().endsWith(".xml")) {
+ ConfigPersister.getInstance().load(f);
+ _saved = true;
+ } else {
+ ConfigPersister.getInstance().loadVersion1(f);
+ _saved = false;
+ }
+ _configForm.put(ConfigPersister.getInstance().getConfig());
+ showConfigName(f);
+ setRunEnabled(false);
+ }
+ } catch (ConfigPersisterException ex) {
+ warn(ex.getMessage());
+ } catch (BindingException ex) {
+ warn(ex.getMessage());
+ }
+ }
+ }
+
+ private class SaveActionListener implements ActionListener {
+ public void actionPerformed(ActionEvent e) {
+ save();
+ }
+ }
+
+ private class BuildActionListener implements ActionListener {
+ public void actionPerformed(ActionEvent e) {
+ final Log log = Log.getSwingLog(_configForm.getLogTextArea());
+ try {
+ if ((!_saved || _configForm.isModified())
+ && !save()) {
+ return;
+ }
+ log.clear();
+ ConfigPersister.getInstance().getConfig().checkInvariants();
+ Builder b = new Builder(log);
+ _outfile = b.build();
+ setRunEnabled(ConfigPersister.getInstance().getConfig()
+ .getHeaderType() == Config.GUI_HEADER // TODO fix console app test
+ && (Util.WINDOWS_OS || !ConfigPersister.getInstance()
+ .getConfig().isDontWrapJar()));
+ } catch (InvariantViolationException ex) {
+ setRunEnabled(false);
+ ex.setBinding(_configForm.getBinding(ex.getProperty()));
+ warn(ex);
+ } catch (BuilderException ex) {
+ setRunEnabled(false);
+ log.append(ex.getMessage());
+ }
+ }
+ }
+
+ private class RunActionListener implements ActionListener {
+ public void actionPerformed(ActionEvent e) {
+ try {
+ getGlassPane().setVisible(true);
+ Worker.post(new Task() {
+ public Object run() throws ExecException {
+ Log log = Log.getSwingLog(_configForm.getLogTextArea());
+ log.clear();
+ String path = _outfile.getPath();
+ if (Util.WINDOWS_OS) {
+ log.append(Messages.getString("MainFrame.executing") + path);
+ Util.exec(new String[] { path }, log);
+ } else {
+ log.append(Messages.getString("MainFrame.jar.integrity.test")
+ + path);
+ Util.exec(new String[] { "java", "-jar", path }, log);
+ }
+ return null;
+ }
+ });
+ } catch (Exception ex) {
+ // XXX errors logged by exec
+ } finally {
+ getGlassPane().setVisible(false);
+ }
+ };
+ }
+
+ private class AboutActionListener implements ActionListener {
+ public void actionPerformed(ActionEvent e) {
+ info(Main.getDescription());
+ }
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/Messages.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/Messages.java
new file mode 100755
index 000000000..5e1c64110
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/Messages.java
@@ -0,0 +1,55 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package net.sf.launch4j.formimpl;
+
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+public class Messages {
+ private static final String BUNDLE_NAME = "net.sf.launch4j.formimpl.messages";
+
+ private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle
+ .getBundle(BUNDLE_NAME);
+
+ private Messages() {
+ }
+
+ public static String getString(String key) {
+ try {
+ return RESOURCE_BUNDLE.getString(key);
+ } catch (MissingResourceException e) {
+ return '!' + key + '!';
+ }
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/MessagesFormImpl.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/MessagesFormImpl.java
new file mode 100755
index 000000000..c05d7f047
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/MessagesFormImpl.java
@@ -0,0 +1,58 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on Oct 7, 2006
+ */
+package net.sf.launch4j.formimpl;
+
+import net.sf.launch4j.binding.Bindings;
+import net.sf.launch4j.config.Msg;
+import net.sf.launch4j.form.MessagesForm;
+
+/**
+ * @author Copyright (C) 2006 Grzegorz Kowal
+ */
+public class MessagesFormImpl extends MessagesForm {
+
+ public MessagesFormImpl(Bindings bindings) {
+ Msg m = new Msg();
+ bindings.addOptComponent("messages", Msg.class, _messagesCheck)
+ .add("messages.startupErr", _startupErrTextArea, m.getStartupErr())
+ .add("messages.bundledJreErr", _bundledJreErrTextArea, m.getBundledJreErr())
+ .add("messages.jreVersionErr", _jreVersionErrTextArea, m.getJreVersionErr())
+ .add("messages.launcherErr", _launcherErrTextArea, m.getLauncherErr())
+ .add("messages.instanceAlreadyExistsMsg", _instanceAlreadyExistsMsgTextArea,
+ m.getInstanceAlreadyExistsMsg());
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/SingleInstanceFormImpl.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/SingleInstanceFormImpl.java
new file mode 100755
index 000000000..c916a9184
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/SingleInstanceFormImpl.java
@@ -0,0 +1,54 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/**
+ * Created on 2007-09-22
+ */
+package net.sf.launch4j.formimpl;
+
+import net.sf.launch4j.binding.Bindings;
+import net.sf.launch4j.config.SingleInstance;
+import net.sf.launch4j.form.SingleInstanceForm;
+
+/**
+ * @author Copyright (C) 2007 Grzegorz Kowal
+ */
+public class SingleInstanceFormImpl extends SingleInstanceForm {
+
+ public SingleInstanceFormImpl(Bindings bindings) {
+ bindings.addOptComponent("singleInstance", SingleInstance.class,
+ _singleInstanceCheck)
+ .add("singleInstance.mutexName", _mutexNameField)
+ .add("singleInstance.windowTitle", _windowTitleField);
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/SplashFormImpl.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/SplashFormImpl.java
new file mode 100755
index 000000000..7413d4a21
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/SplashFormImpl.java
@@ -0,0 +1,61 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on May 1, 2006
+ */
+package net.sf.launch4j.formimpl;
+
+import javax.swing.JFileChooser;
+
+import net.sf.launch4j.FileChooserFilter;
+import net.sf.launch4j.binding.Bindings;
+import net.sf.launch4j.config.Splash;
+import net.sf.launch4j.form.SplashForm;
+
+/**
+ * @author Copyright (C) 2006 Grzegorz Kowal
+ */
+public class SplashFormImpl extends SplashForm {
+
+ public SplashFormImpl(Bindings bindings, JFileChooser fc) {
+ bindings.addOptComponent("splash", Splash.class, _splashCheck)
+ .add("splash.file", _splashFileField)
+ .add("splash.waitForWindow", _waitForWindowCheck, true)
+ .add("splash.timeout", _timeoutField, "60")
+ .add("splash.timeoutErr", _timeoutErrCheck, true);
+
+ _splashFileButton.addActionListener(new BrowseActionListener(false, fc,
+ new FileChooserFilter("Bitmap files (.bmp)", ".bmp"), _splashFileField));
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/VersionInfoFormImpl.java b/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/VersionInfoFormImpl.java
new file mode 100755
index 000000000..c2f60d1d3
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/VersionInfoFormImpl.java
@@ -0,0 +1,63 @@
+/*
+ Launch4j (http://launch4j.sourceforge.net/)
+ Cross-platform Java application wrapper for creating Windows native executables.
+
+ Copyright (c) 2004, 2007 Grzegorz Kowal
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification,
+ are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Launch4j nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Created on May 1, 2006
+ */
+package net.sf.launch4j.formimpl;
+
+import javax.swing.JFileChooser;
+
+import net.sf.launch4j.binding.Bindings;
+import net.sf.launch4j.config.VersionInfo;
+import net.sf.launch4j.form.VersionInfoForm;
+
+/**
+ * @author Copyright (C) 2006 Grzegorz Kowal
+ */
+public class VersionInfoFormImpl extends VersionInfoForm {
+
+ public VersionInfoFormImpl(Bindings bindings, JFileChooser fc) {
+ bindings.addOptComponent("versionInfo", VersionInfo.class, _versionInfoCheck)
+ .add("versionInfo.fileVersion", _fileVersionField)
+ .add("versionInfo.productVersion", _productVersionField)
+ .add("versionInfo.fileDescription", _fileDescriptionField)
+ .add("versionInfo.internalName", _internalNameField)
+ .add("versionInfo.originalFilename", _originalFilenameField)
+ .add("versionInfo.productName", _productNameField)
+ .add("versionInfo.txtFileVersion", _txtFileVersionField)
+ .add("versionInfo.txtProductVersion", _txtProductVersionField)
+ .add("versionInfo.companyName", _companyNameField)
+ .add("versionInfo.copyright", _copyrightField);
+ }
+}
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/messages.properties b/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/messages.properties
new file mode 100755
index 000000000..53a2442a8
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/messages.properties
@@ -0,0 +1,74 @@
+#
+# Launch4j (http://launch4j.sourceforge.net/)
+# Cross-platform Java application wrapper for creating Windows native executables.
+#
+# Copyright (c) 2004, 2007 Grzegorz Kowal
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification,
+# are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+# * Neither the name of the Launch4j nor the names of its contributors
+# may be used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+tab.basic=Basic
+tab.classpath=Classpath
+tab.header=Header
+tab.singleInstance=Single instance
+tab.jre=JRE
+tab.envVars=Set env. variables
+tab.splash=Splash
+tab.version=Version Info
+tab.messages=Messages
+
+# Basic
+jar=Jar:
+jarPath=Jar runtime path:
+jarTip=Application jar.
+jarPathTip=Optional runtime path of the jar relative to the executable. For example, if the executable launcher and the application jar named calc.exe and calc.jar are in the same directory, it would be: calc.jar.
+
+# Classpath
+specifyClassPath=Specify classpath item to add.
+confirmClassPathRemoval=Remove selected classpath items?
+noManifest=The selected jar does not have a manifest.
+
+# JRE
+specifyVar=Specify environment variable to add.
+otherVar=Other var
+jdkPreference.jre.only=Only use public JREs
+jdkPreference.prefer.jre=Prefer public JRE, but use JDK runtime if newer
+jdkPreference.prefer.jdk=Prefer JDK runtime, but use public JRE if newer
+jdkPreference.jdk.only=Only use private JDK runtimes
+
+MainFrame.config.files=launch4j config files (.xml, .cfg)
+MainFrame.new.config=New configuration
+MainFrame.open.config=Open configuration or import 1.x
+MainFrame.save.config=Save configuration
+MainFrame.build.wrapper=Build wrapper
+MainFrame.test.wrapper=Test wrapper
+MainFrame.about.launch4j=About launch4j
+MainFrame.discard.changes=Discard changes?
+MainFrame.confirm=Confirm
+MainFrame.untitled=untitled
+MainFrame.executing=Executing:
+MainFrame.jar.integrity.test=Jar integrity test, executing:
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/messages_es.properties b/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/messages_es.properties
new file mode 100755
index 000000000..1d2fac25f
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/formimpl/messages_es.properties
@@ -0,0 +1,56 @@
+#
+# Launch4j (http://launch4j.sourceforge.net/)
+# Cross-platform Java application wrapper for creating Windows native executables.
+#
+# Copyright (c) 2004, 2007 Grzegorz Kowal, Patricio Martínez Ros
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification,
+# are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+# * Neither the name of the Launch4j nor the names of its contributors
+# may be used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+tab.basic = B\u00E1sico
+tab.header = Cabecera
+tab.jre = JRE
+tab.splash = Pantalla de bienvenida
+tab.version = Informaci\u00F3n de la versi\u00F3n
+
+jar = Jar
+jarPath = Ruta del jar
+jarTip = Jar de la aplicaci\u00F3n.
+jarPathTip = Ruta del jar relativa al ejecutable. Por ejemplo, si el lanzador ejecutable y el jar de la aplicaci\u00F3n, llamados calc.exe y calc.jar respectivamente, est\u00E1n en el mismo directorio, ser\u00EDa\: calc.jar.
+
+MainFrame.config.files = Ficheros de configuraci\u00F3n de launch4j (.xml, .cfg)
+MainFrame.new.config = Nueva configuraci\u00F3n
+MainFrame.open.config = Abrir configuraci\u00F3n o importar 1.x
+MainFrame.save.config = Guardar configuraci\u00F3n
+MainFrame.build.wrapper = Construir el empaquetador
+MainFrame.test.wrapper = Comprobar el empaquetador
+MainFrame.about.launch4j = Acerca de launch4j
+MainFrame.discard.changes = \u00BFDescartar cambios?
+MainFrame.confirm = Confirmar
+MainFrame.untitled = Sin nombre
+MainFrame.executing = Ejecutando\:
+MainFrame.jar.integrity.test = Prueba de integridad jar, ejecutando\:
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/messages.properties b/build/windows/launcher/launch4j/src/net/sf/launch4j/messages.properties
new file mode 100755
index 000000000..cf28d15af
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/messages.properties
@@ -0,0 +1,45 @@
+#
+# Launch4j (http://launch4j.sourceforge.net/)
+# Cross-platform Java application wrapper for creating Windows native executables.
+#
+# Copyright (c) 2004, 2007 Grzegorz Kowal
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification,
+# are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+# * Neither the name of the Launch4j nor the names of its contributors
+# may be used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+Main.usage=usage
+
+Builder.compiling.resources=Compiling resources
+Builder.linking=Linking
+Builder.wrapping=Wrapping
+Builder.success=Successfully created
+Builder.generated.resource.file=Generated resource file...\n
+Builder.line.has.errors=Line {0} has errors...
+
+Util.exec.failed=Exec failed
+Util.tmpdir=Temporary file directory path (launch4j.tmpdir) cannot contain spaces.
+Util.use.double.backslash=Use \\\\ to code Windows paths in fields that don't represent files or paths!
diff --git a/build/windows/launcher/launch4j/src/net/sf/launch4j/messages_es.properties b/build/windows/launcher/launch4j/src/net/sf/launch4j/messages_es.properties
new file mode 100755
index 000000000..b179d9bd5
--- /dev/null
+++ b/build/windows/launcher/launch4j/src/net/sf/launch4j/messages_es.properties
@@ -0,0 +1,45 @@
+#
+# Launch4j (http://launch4j.sourceforge.net/)
+# Cross-platform Java application wrapper for creating Windows native executables.
+#
+# Copyright (c) 2004, 2007 Grzegorz Kowal, Patricio Martínez Ros
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification,
+# are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+# * Neither the name of the Launch4j nor the names of its contributors
+# may be used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+Main.usage=Uso
+
+Builder.compiling.resources=Compilando recursos
+Builder.linking=Enlazando
+Builder.wrapping=Empaquetando
+Builder.success=Creado con \ufffdxito
+Builder.generated.resource.file=Fichero de recursos generado...\n
+Builder.line.has.errors=Line {0} has errors...
+
+Util.exec.failed=Fallo en la ejecuci\ufffd
+Util.tmpdir=Temporary file directory path (launch4j.tmpdir) cannot contain spaces.
+Util.use.double.backslash=Use \\\\ to code Windows paths in fields that don't represent files or paths!
\ No newline at end of file
diff --git a/build/windows/launcher/launch4j/w32api/MinGW.LICENSE.txt b/build/windows/launcher/launch4j/w32api/MinGW.LICENSE.txt
new file mode 100755
index 000000000..141412dd9
--- /dev/null
+++ b/build/windows/launcher/launch4j/w32api/MinGW.LICENSE.txt
@@ -0,0 +1,25 @@
+MinGW - Licensing Terms
+
+Various pieces distributed with MinGW come with its own copyright and license:
+
+Basic MinGW runtime
+ MinGW base runtime package is uncopyrighted and placed in the public domain.
+ This basically means that you can do what you want with the code.
+
+w32api
+ You are free to use, modify and copy this package.
+ No restrictions are imposed on programs or object files compiled with this library.
+ You may not restrict the the usage of this library.
+ You may distribute this library as part of another package or as a modified package
+ if and only if you do not restrict the usage of the portions consisting
+ of this (optionally modified) library.
+ If distributed as a modified package then this file must be included.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty
+ of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+MinGW profiling code
+ MinGW profiling code is distributed under the GNU General Public License.
+
+The development tools such as GCC, GDB, GNU Make, etc all covered by GNU General Public License.
diff --git a/build/windows/launcher/launch4j/w32api/libadvapi32.a b/build/windows/launcher/launch4j/w32api/libadvapi32.a
new file mode 100755
index 000000000..c471853c7
Binary files /dev/null and b/build/windows/launcher/launch4j/w32api/libadvapi32.a differ
diff --git a/build/windows/launcher/launch4j/w32api/libgcc.a b/build/windows/launcher/launch4j/w32api/libgcc.a
new file mode 100755
index 000000000..d3f89479e
Binary files /dev/null and b/build/windows/launcher/launch4j/w32api/libgcc.a differ
diff --git a/build/windows/launcher/launch4j/w32api/libkernel32.a b/build/windows/launcher/launch4j/w32api/libkernel32.a
new file mode 100755
index 000000000..5d3eb074f
Binary files /dev/null and b/build/windows/launcher/launch4j/w32api/libkernel32.a differ
diff --git a/build/windows/launcher/launch4j/w32api/libmingw32.a b/build/windows/launcher/launch4j/w32api/libmingw32.a
new file mode 100755
index 000000000..d1f7888d8
Binary files /dev/null and b/build/windows/launcher/launch4j/w32api/libmingw32.a differ
diff --git a/build/windows/launcher/launch4j/w32api/libmsvcrt.a b/build/windows/launcher/launch4j/w32api/libmsvcrt.a
new file mode 100755
index 000000000..6714146b6
Binary files /dev/null and b/build/windows/launcher/launch4j/w32api/libmsvcrt.a differ
diff --git a/build/windows/launcher/launch4j/w32api/libshell32.a b/build/windows/launcher/launch4j/w32api/libshell32.a
new file mode 100755
index 000000000..d35fbdaf3
Binary files /dev/null and b/build/windows/launcher/launch4j/w32api/libshell32.a differ
diff --git a/build/windows/launcher/launch4j/w32api/libuser32.a b/build/windows/launcher/launch4j/w32api/libuser32.a
new file mode 100755
index 000000000..387fb650d
Binary files /dev/null and b/build/windows/launcher/launch4j/w32api/libuser32.a differ
diff --git a/build/windows/launcher/launch4j/web/bullet.gif b/build/windows/launcher/launch4j/web/bullet.gif
new file mode 100755
index 000000000..f3f133bb8
Binary files /dev/null and b/build/windows/launcher/launch4j/web/bullet.gif differ
diff --git a/build/windows/launcher/launch4j/web/changelog.html b/build/windows/launcher/launch4j/web/changelog.html
new file mode 100755
index 000000000..83511a554
--- /dev/null
+++ b/build/windows/launcher/launch4j/web/changelog.html
@@ -0,0 +1,356 @@
+
+
+
+ Launch4j - Cross-platform Java executable wrapper
+
+
+
+
+
+
+
+
FR #1707827 Allow to prefer JDK private runtimes over JREs (Ian Roberts).
+
FR #1730245 Allow to run only a single aplication instance (Sylvain Mina).
+
FR #1391610 Added IBM JRE/JDK support.
+
Added environment variable expansion in bundled JRE path.
+
Fixed critical bug #1882524 JRE detection problem on 64-bit Windows.
+
Fixed bug #1758912 Vista elevation to full administrator privileges.
+
Fixed bug #1784341 Problems with spaces in paths under linux (Michael Piefel).
+
Fixed bug where /bin was appended to path environment variable instead of jre_path/bin.
+
+
+
Changed license to BSD, MIT (26-01-2008)
+
+
+ The upcoming Launch4j 3.0.0 release will be licensed under the much more
+ liberal new BSD license. The head subproject (the binary header attached to wrapped jars)
+ will be licensed under the similar MIT license.
+
+
+
+
Changes in version 3.0.0-pre2 (29-10-2006)
+
+
Enhanced GUI.
+
Redesigned error reporting.
+
Added custom error messages.
+
Added support website feature.
+
Added PWD and OLDPWD special variables and access to the registry.
+
Runtime ini file extension changed to .l4j.ini, added comments (#).
+
FR #1427811 Initial process priority.
+
FR #1547339 Added VarFileInfo structure to Version Info (Stephan Laertz).
+
FR #1584295 Updated documentation for --l4j-debug.
+
Fixed <jarArgs/> and <args/> config conversion bug (found by Dafe Simonek).
+
Fixed the Ant task exception reporting bug, added tmpdir and bindir attributes.
+
Fixed bug #1563415 Problem with launching application when ini file exists (found by mojomax).
+
Fixed bug #1527619 Console header wildcard expansion (found by erikjv).
+
Fixed bug #1544167 NPE when dontwrap and only classpath given (found by Hendrik Schreiber).
+
Fixed bug #1584264 Dropdown boxes get mixed up (found by Larsen).
Improved configuration file format and embedded Ant config.
+
Launch executable jars, regular jars and class files.
+
Added dynamic classpath resolution with environment variable references and wildcards.
+
Added option to set environment variables before launching the application.
+
New command line switches to change the compiled options.
+
Improved debug information.
+
Added support for XP visual style manifests.
+
Added option to disable use of private JREs.
+
Many small fixes and improvements...
+
+
+
Configuration file changes in 3.x
+
+
Previous formats (1.x and 2.x) are supported.
+
<headerType> accepts gui|console
+
<jarArgs> was changed to <cmdLine>
+
+ <launch4jConfig><headerObjects><file> was changed to
+ <launch4jConfig><obj>
+
+
+ <launch4jConfig><libs><file> was changed to
+ <launch4jConfig><lib>
+
+
+ <launch4jConfig><jre><args> was changed to multiple
+ <launch4jConfig><jre><opt>
+
+
+
+
Embedded Ant configuration changes in 3.x
+
+
+ <jre args="value"> was changed to
+ <jre><opt>value</opt></jre>
+
+
Now it's possible to define headerObjects, libs and classpath.
+
+
+
Changes in version 2.1.5 (21-07-2006)
+
+
Changed the Java download site to http://java.com/download.
+
Now it's possible to use absolute and relative paths to specify the bundled JRE.
+
+
+
Changes in version 2.1.4 (15-06-2006)
+
+
+ Fixed bug #1503996 Only the first wrapper instance had a custom process name
+ (found by Helge Böhme).
+
+
+
+
Changes in version 2.1.3 (31-05-2006)
+
+
+ Fixed bug #1497453 Ant task doesn't support relative jar path with '..'
+ (found by Aston, Pavel Moukhataev).
+
+
Jar argument size limit is now 16KB.
+
Environment variable size limit raised to 32KB.
+
Allow to concatenate multiple env. variables in one property (Maria D.)
+
Added launch4j.tmpdir property.
+
+
+
Changes in version 2.1.2 (03-04-2006)
+
+
Important bugfix: insufficient command line buffer size was increased to 32KB
+ (found by Sebastian Kopsan).
+
Added runtime JVM options from an .ini file.
+
Launch4j's bin directory is now configurable through launch4j.bindir
+ system property.
+
+
+
Changes in version 2.1.1 (25-01-2006)
+
+
Fixed bug #1402748. Validation error occurred when using an Ant task with
+ embedded config and dontWrapJar option (found by Chris Nokleberg).
+
+
+
Changes in version 2.1.0 (10-01-2006)
+
+
More features and smaller header: 18 KB!!
+
Added launcher mode, you can choose whether or not to wrap the jar.
+
Spanish translation of the website/docs and program messages
+ (Patricio MartÃnez Ros).
+
JRE's bin directory is appended to the Path environment variable
+ (Ianiv Schweber).
+
Added special variables EXEDIR and EXEFILE that hold the executable's
+ directory and full path.
+
Support for mapping environment variables to system properties.
+
Added debug launching mode - various information is displayed before
+ starting the Java application.
+
Fixed min/max JRE version checking, previous versions allowed these
+ to be equal (found by Ryan).
+
Bug fixed. Quotes in jar/JVM arguments were handled incorrectly (found by Juan Alvarez Ferrando).
+
A few other enhancements.
+
+
+
Changes in version 2.0.0 (31-10-2005)
+
+
Launch4j for Mac OS X is available thanks to Peter Centgraf.
+
Added support for custom headers.
+
Fixed bug #1343908, command line arguments with spaces were handled
+ incorrectly by the console header (found by Oliver Schaefer / Steve Alberty).
+
Fixed stdin redirection bug (found by Timo Santasalo).
+
+
+
Changes in version 2.0 RC3 (13-08-2005) - final RC
+
+
Correct handling of pathnames with spaces.
+
Fixed the '%20' pathname bug.
+
Fixed basedir bug (Richard Xing).
+
Splash screen can be closed when the application window becomes visible
+ with out specifying it's title (Martin Busik).
+ Update your config file: <waitForTitle>title</waitForTitle>
+ is now <waitForWindow>true</waitForWindow>.
+
+
Fixed build.bat files in demo directories.
+
+
+
Changes in version 2.0 RC2 (21-06-2005)
+
+
chdir allows to change the current directory to arbitrary paths
+ relative to the executable (FR #1144907). It's incompatible with
+ previous versions, update your config file:
+ <chdir>true</chdir>
+ is now <chdir>.</chdir>.
+
+
Bundled JRE path no longer depends on chdir function.
+
Fixed Ant task bug, build files outside launch4j's directory
+ wouldn't work. Josh Elsasser submitted a patch that works without
+ setting launch4j's home dir in the build file. Thanks!
+
+
Removed static edge from splash screen (Serge Baranov).
+
Program checks that the output file path doesn't contain spaces.
+
Fixed a NPE bug caused by a missing maxVersion property
+ (found by Morgan Schweers).
+
+
Fixed relative JRE path bug (found by Nili_).
+
Cleaned up the Builder class.
+
Fixed Ant task NPE where the config was entirely defined in the
+ build file (Josh Elsasser).
+
+
+
+
Changes in version 2.0 RC (07-06-2005)
+
+
Added an Ant task for better build integration.
+
Added 2.x documentation.
+
Updated the demo configuration files.
+
Fixed issues with relative paths in the configuration.
+
Removed the '-1' option in console mode.
+
Minor fixes.
+
+
+
Changes in version 2.0 beta2 (23-05-2005)
+
+
# comments are recognized when importing 1.x cfg files.
+
Added version information.
+
Resource file is displayed when a resource error occurs.
+
Fixed a bug found by Max, options on the first tab were always enabled.
+
+
+
Changes in version 2.0 beta1 (13-05-2005)
+
+
Completely new, cross-platform wrapper - create windows executables on Linux.
+
New .xml configuration file.
+
Application icon with multiple resolutions and color depths.
+
Swing GUI interface.
+
Header compiled with MinGW port of gcc instead of VC++.
+
+
+
Changes in version 1.4.2 (12-03-2005)
+
+
Fixed bug #1158143, stayAlive without a splash screen caused
+ an infinite loop (found by Gregory Kotsaftis).
+
+
+
+
Changes in version 1.4.1 (04-03-2005)
+
+
Fixed bug #1119040, buffer for reading config properties
+ was too short (found by Tom Jensen and Neil).
+
+
Added configurable splash timeout (FR #1102951).
+
Added option to disable the error message on splash timeout (FR #1109159).
+
Option to keep the gui launcher 'alive' after starting an application (FR #1124653).
+
Removed version info.
+
'waitfor' property is now optional.
+
+
+
Changes in version 1.4.0 (26-01-2005)
+
+
Removed .lch4j suffix from process name, now it has the
+ form of the executable filename. The temporary launchers are stored in
+ launch4j-tmp directory (suggested by Emmanuel).
+
+
Added support for console apps (FR #1050053).
+
+
+
Changes in version 1.3.1 (05-11-2004)
+
+
Fixed a bug where explorer window was opened instead of
+ launching the application when setProcName was set to false
+ (found by Rob Jones).
+
+
Fixed temporary launcher deletion bug.
+
+
+
Changes in version 1.3.0 (01-11-2004)
+
+
Now you can configure launch4j to:
+
+
Use a bundled JRE.
+
Search for java, show an error message if the
+ right version cannot be found and open the java download page.
+
And a feature you asked for: use bundled JRE, if
+ that fails search for java and bring up the java download page on error.
+
+
+
Enhanced code that sets the custom process name. In
+ case launch4j can't refresh the temporary launcher, bundled JRE on a
+ read only file system for example, it will use one created previously,
+ if it's present and has the correct size. If not, launching will still
+ continue, but with javaw.exe process name.Temporary launchers are
+ now created in the jre directory instead of jre/bin.
+
+
errTitle property allows to set the title of the error message box.
+
+
+
Changes in version 1.2.1 (25-09-2004)
+
+
Bugfix that allows launching from command line using short
+ name (#1026514 / found by Zach Del)
+
+
+
+
Changes in version 1.2.0 (10-09-2004)
+
+
Custom process name (myapp.lch4j.exe)
+
9 KB stub!
+
Jar arguments
+
Bugfix that allows launching from command line.
+
Hide splash on javaw error.
+
Easier configuration with case insensitive parameters + show unrecognized parameter.
+
12 KB demo application, 34 KB with splash screen.
+
Configuration parameter 'args' changed to 'jvmArgs'
+Run launch4j.exe or launch4j script without command
+line arguments to enter the GUI mode.
+
+
launch4j.exe
+
+To wrap a jar in console mode use launch4jc.exe and
+specify the configuration file.
+
+
launch4jc.exe config.xml
+
+On Linux use the launch4j script.
+
+
launch4j ./demo/l4j/config.xml
+
+
Configuration file
+Launch4j requires an xml configuration file for each output executable.
+You can create and edit it conveniently using the graphic user
+interface or your favorite editor. Alternatively it's possible to pass
+all of the configuration parameters through the Ant task. All files
+may be absolute paths or relative to the configuration file path.
+
+
+ Type of the header used to wrap the application.
+
+
+
+
Header type
+
Launcher
+
Splash screen
+
Wait for the application to close
+
+
+
+
+
gui
+
javaw
+
yes
+
wrapper waits only if stayAlive is set to true,
+ otherwise it terminates immediately or after closing
+ the splash screen.
+
+
+
+
console
+
java
+
no
+
always waits and returns application's exit code.
+
+
+
+
+
+
+
<outfile>
+
Output executable file.
+
+
+
<jar>
+
+ Optional, by default specifies the jar to wrap. To launch a jar without
+ wrapping it enter the runtime path of the jar relative to
+ the executable and set <dontWrapJar> to true.
+ For example, if the executable launcher and the application jar named
+ calc.exe and calc.jar are in the same directory
+ then you would use <jar>calc.jar</jar>
+ and <dontWrapJar>true</dontWrapJar>.
+
+
+
+
<dontWrapJar>
+
+ Optional, defaults to false. Launch4j by default wraps jars in native
+ executables, you can prevent this by setting <dontWrapJar> to true.
+ The exe acts then as a launcher and starts the application specified in
+ <jar> or <classPath><mainClass>
+
+
+
+
<errTitle>
+
+ Optional, sets the title of the error message box that's displayed if Java cannot
+ be found for instance. This usually should contain the name of your
+ application. The console header prefixes error messages with this
+ property (myapp: error...)
+
+
+
+
<cmdLine>
+
Optional, constant command line arguments.
+
+
+
<chdir>
+
Optional. Change current directory to an arbitrary path relative to the executable.
+ If you omit this property or leave it blank it will have no effect.
+ Setting it to . will change the current dir to the same directory
+ as the executable. .. will change it to the parent directory, and so on.
+
+
+
<chdir>.</chdir>
+
+
+
<chdir>../somedir</chdir>
+
+
+
+
<customProcName>
+
Optional, defaults to false.
+ Set the process name as the executable filename and use Xp style manifests
+ (if any).
+ Creates a temporary file in launch4j-tmp directory inside the used JRE.
+ These files are deleted by any launch4j wrapped application, which sets
+ the process name and uses the same JRE. The removal takes place
+ when the application starts,
+ so at least one copy of this file will always be present.
+
+
+
+
<stayAlive>
+
Optional, defaults to false in GUI header, always true in console header.
+ When enabled the launcher waits for the Java application
+ to finish and returns it's exit code.
+
+
+
+
<icon>
+
Application icon in ICO format. May contain multiple color depths/resolutions.
+
+
+
<obj>
+
Optional, custom headers only. Ordered list of header object files.
+
+
+
<lib>
+
Optional, custom headers only. Ordered list of libraries used by header.
+
+
+
<singleInstance>
+
Optional, allow to run only a single instance of the application.
+
+
+
+
<mutexName>
+
Unique mutex name that will identify the application.
+
<windowTitle>
+
Optional, recognized by GUI header only. Title or title part of a window
+ to bring up instead of running a new instance.
+
+
+
+
+
<jre>
+
Required element that groups JRE settings.
+
+
+
+
<path>, <minVersion>, <maxVersion>
+
The <path> property is used
+ to specify the absolute or relative path (to the executable) of a bundled JRE, it
+ does not rely on the current directory or <chdir>.
+ Note that this path is not checked until the actual application execution.
+ If you'd like the wrapper to search for a JRE (public or SDK private)
+ use the <minVersion> property, you may also specify
+ the <maxVersion> to prevent it from using higher Java versions.
+ Launch4j will always use the highest version available (in the min/max range of course).
+ If a Sun's JRE is not available or does not satisfy the search criteria,
+ the search will be repeated on IBM runtimes.
+ You can also combine these properties to change the startup process...
+
+
+
+
+
<path>
+
Run if bundled JRE and javaw.exe are present, otherwise stop with error.
+
<path> + <minVersion> [+ <maxVersion>]
+
Use bundled JRE first, if it cannot be located search for Java,
+ if that fails display error message and open the Java download page.
+
+
<minVersion> [+ <maxVersion>]
+
Search for Java, if an appropriate version cannot be found display
+ error message and open the Java download page.
+
+
+
+
+
+
+
<jdkPreference>
+
Optional, defaults to preferJre; Allows you to specify a preference
+ for a public JRE or a private JDK runtime. Valid values are:
+
+
+
+
+
jreOnly
+
Always use a public JRE (equivalent to the
+ old option dontUsePrivateJres=true)
+
preferJre
+
Prefer a public JRE, but use a JDK private
+ runtime if it is newer than the public
+ JRE (equivalent to the old option
+ dontUsePrivateJres=false)
+
preferJdk
+
Prefer a JDK private runtime, but use a
+ public JRE if it is newer than the
+ JDK
+
jdkOnly
+
Always use a private JDK runtime (fails
+ if there is no JDK installed)
+
+
+
+
HeapSize, HeapPercent
+
If size and percent are specified, then the setting which yields
+ more memory will be chosen at runtime. In other words, setting both values
+ means: percent of free memory no less than size in MB.
+
+
+
+
+
<initialHeapSize>
+
Optional, initial heap size in MB.
+
+
+
<initialHeapPercent>
+
Optional, initial heap size in % of free memory.
+
+
+
<maxHeapSize>
+
Optional, max heap size in MB.
+
+
+
<maxHeapPercent>
+
Optional, max heap size in % of free memory.
+
+
+
+
<opt>
+
Optional, accepts everything you would normally pass to
+ java/javaw launcher: assertion options, system properties and X options.
+ Here you can map environment and special variables EXEDIR
+ (exe's runtime directory), EXEFILE (exe's runtime full file path)
+ to system properties. All variable references must be surrounded with
+ percentage signs and quoted.
+
Optional, groups the splash screen settings. Allowed only in GUI header.
+
+
+
+
<file>
+
Splash screen image in BMP format.
+
+
+
<waitForWindow>
+
Optional, defaults to true. Close the splash screen when an application
+ window or Java error message box appears. If set to false,
+ the splash screen will be closed on timeout.
+
+
+
+
<timeout>
+
Optional, defaults to 60. Number of seconds after which the splash screen
+ must be closed. Splash timeout may cause an error depending on
+ <timeoutErr>.
+
+
+
+
<timeoutErr>
+
Optional, defaults to true. True signals an error on splash timeout,
+ false closes the splash screen quietly.
+
+
+
+
+
+
<versionInfo>
+
Optional, version information to be displayed by the Windows Explorer.
+
+
+
+
<fileVersion>
+
Version number 'x.x.x.x'
+
+
+
<txtFileVersion>
+
Free form file version, for example '1.20.RC1'.
+
+
+
<fileDescription>
+
File description presented to the user.
+
+
+
<copyright>
+
Legal copyright.
+
+
+
<productVersion>
+
Version number 'x.x.x.x'
+
+
+
<txtProductVersion>
+
Free form file version, for example '1.20.RC1'.
+
+
+
<productName>
+
Text.
+
+
+
<companyName>
+
Optional text.
+
+
+
<internalName>
+
Internal name without extension, original filename or module name for example.
+
+
+
<originalFilename>
+
Original name of the file without the path. Allows to determine
+ whether a file has been renamed by a user.
+
+
+
+
+
Importing 1.x configuration
+It's possible to import a 1.x configuration file using the GUI
+interface. Open the file, correct the paths and save it as a new xml
+configuration.
+
+
Ant task
+You may set a launch4j directory property or change the task definition.
+
+
+
+You can also define the entire configuration in the task, but it will
+not be possible to edit such a file in the GUI mode. All paths except
+for <chdir>, <jre><path> and jarPath
+are calculated using the basedir project attribute.
+
+
+When you create a wrapper or launcher all configuration details are compiled into the
+executable and cannot be changed without recreating it or hacking with a resource editor.
+Launch4j 2.1.2 introduces a new feature that allows to pass additional JVM options
+at runtime from an .l4j.ini file. Now you can specify the options in the configuration file,
+ini file or in both, but you cannot override them. The ini file's name must correspond
+to the executable's (myapp.exe : myapp.l4j.ini).
+The arguments should be separated with spaces or new lines, environment variable
+expansion is supported, for example:
+
+ To make sure the output executable is configured correctly you can use the
+ debug launching mode to log various information to the launch4j.log file.
+
+
+
--l4j-default-proc
+
+ Use default process name.
+
+
+
--l4j-dont-wait
+
+ Disable the "stay alive" function.
+
+
+
--l4j-no-splash
+
+ Disable the splash screen.
+
+
+
--l4j-no-splash-err
+
+ Disable splash screen error on timeout, might be useful on very slow computers.
+
+
+
+
Settings
+
+
Alternate bin directory: launch4j.bindir
+
+ It's possible to override the default bin directory location which contains windres and ld
+ tools using the launch4j.bindir system property. The property can have two forms:
+ a path relative to Launch4j's directory (altbin for example) or an absolute path.
+
+
+
Working directory: launch4j.tmpdir
+
Change the working directory if the default path contains spaces which windres cannot handle.
+ Launch4j is a cross-platform tool for wrapping
+ Java applications distributed as jars in lightweight Windows
+ native executables. The executable can be
+ configured to search for a certain JRE version or
+ use a bundled one, and it's possible to set
+ runtime options, like the initial/max heap size.
+ The wrapper also provides better user experience
+ through an application icon, a native pre-JRE
+ splash screen, a custom process name, and a Java
+ download page in case the appropriate JRE cannot
+ be found.
+
+
+
Features
+
+
Launch4j wraps jars in Windows native executables and allows to run them
+ like a regular Windows program. It's possible to wrap applications
+ on Windows, Linux, Mac OS X and Solaris!
+
+
Also creates launchers for jars and class files without wrapping.
+
+ Supports executable jars and dynamic classpath resolution using
+ environment variables and wildcards.
+
+
Doesn't extract the jar from the executable.
+
Custom application icon with multiple resolutions and color depths.
+
Native pre-JRE splash screen in BMP format shown until
+ the Java application starts.
+
+
Process name as the executable filename to easily
+ identify your application, initial priority and
+ single aplication instance features.
+
+
Works with a bundled JRE or searches for newest Sun or IBM JRE / JDK in given
+ version range.
+
Opens Java download page if an appropriate Java version cannot be
+ found or a support website in case of an error.
+
+
Supports GUI and console apps.
+
Supports Vista manifests and XP visual style manifests.
+
Passes command line arguments, also supports constant arguments.
+
Allows to set the initial/max heap size also dynamically in percent of free memory.
+
JVM options: set system properties, tweak the garbage collection...
+
Runtime JVM options from an .l4j.ini file.
+
Runtime command line switches to change the compiled options.
+
Access to environment variables, the registry and executable file path through system properties.
+
Set environment variables.
+
Option to change current directory to the executable location.
+
The JRE's bin directory is appended to the Path environment variable.
+
Custom version information shown by Windows Explorer.
+
GUI and command line interface.
+
Build integration through an Ant task and a Maven Plugin.
+
Lightweight: 26 KB!
+
It's free and may be used for commercial purposes.
+
Includes a sample application and Ant script
+ that automates the build process from Java sources to native executable.
+
+
The wrapped program works on all Windows platforms (98/Me/NT/2K/XP/Vista),
+ Launch4j works on NT/2K/XP/Vista, Linux, Mac OS X (build on 10.4) and Sparc Solaris 8-10.
+
+
+
License
+
+ This program is free software licensed under the
+ BSD license, the head subproject
+ (the code which is attached to the wrapped jars) is licensed under the
+ MIT license.
+ Launch4j may be used for wrapping closed source, commercial applications.
+
+
Info
+
+ Running Launch4j on other Java enabled platforms is a matter of getting a binary version
+ of MinGW binutils 2.15.90 (windres and ld only)
+ for your system or compiling them. If you'll provide these, I'll be able to create a binary package
+ available for download.
+
+
+
+
+
+
+
diff --git a/build/windows/launcher/launch4j/web/launch4j-use.gif b/build/windows/launcher/launch4j/web/launch4j-use.gif
new file mode 100755
index 000000000..ccb888247
Binary files /dev/null and b/build/windows/launcher/launch4j/web/launch4j-use.gif differ
diff --git a/build/windows/launcher/launch4j/web/launch4j.gif b/build/windows/launcher/launch4j/web/launch4j.gif
new file mode 100755
index 000000000..27552074a
Binary files /dev/null and b/build/windows/launcher/launch4j/web/launch4j.gif differ
diff --git a/build/windows/launcher/launch4j/web/links.html b/build/windows/launcher/launch4j/web/links.html
new file mode 100755
index 000000000..4213b86f9
--- /dev/null
+++ b/build/windows/launcher/launch4j/web/links.html
@@ -0,0 +1,73 @@
+
+
+
+ Launch4j - Cross-platform Java executable wrapper
+
+
+
+
+
+
+
+
+
+
diff --git a/build/windows/launcher/launch4j/web/style.css b/build/windows/launcher/launch4j/web/style.css
new file mode 100755
index 000000000..f57c086d6
--- /dev/null
+++ b/build/windows/launcher/launch4j/web/style.css
@@ -0,0 +1,159 @@
+body, table {
+ font: 12px/20px Verdana, Arial, Helvetica, sans-serif;
+}
+
+
+pre {
+ padding: 8px;
+ border: 1px dashed #999999;
+ background-color: #f1f1f1;
+ font: 13px/20px "Courier New", Courier, monospace;
+}
+
+
+.version {
+ color: #307fe1;
+ font-weight: bold;
+}
+
+
+.codeword {
+ color: #3333ff;
+}
+.attrib {
+ color: #404040;
+}
+.option {
+ font-family: "Courier New", Courier, monospace;
+ font-weight: bold;
+}
+
+
+dt {
+ margin-top: 1.5em;
+ color: #404040;
+ font-size: 115%;
+ border-bottom: 1px solid #cccccc;
+}
+dd {
+ margin-left: 1em;
+}
+
+
+.warn, ul.changes em {
+ color: #ff0000;
+}
+
+
+table {
+ margin-top: 1em;
+ padding: 0;
+ border: 1px solid #999999;
+ border-collapse: collapse;
+ text-align: center;
+}
+table th {
+ padding: 2px 4px;
+ border: 1px solid #999999;
+ background-color: #f1f1f1;
+}
+table td {
+ padding: 2px 4px;
+ border: 1px solid #999999;
+}
+.description {
+ text-align: left;
+}
+
+
+#container {
+ width: 90%;
+ margin: 10px auto;
+ border-width: 0;
+ background-color: #ffffff;
+}
+
+
+#top {
+ padding: 0.5em;
+ background-color: #ffffff;
+}
+#top h1 {
+ margin: 0;
+ padding: 0;
+}
+
+
+#leftnav {
+ float: left;
+ width: 170px;
+ margin: 0;
+ padding: 0.5em;
+ background-color: #ffffff;
+}
+#leftnav ul {
+ margin: 0;
+ padding: 0;
+ border: none;
+ list-style-type: none;
+ font-size: 115%;
+}
+#leftnav a {
+ width: 170px;
+ height: 1.6em;
+ line-height: 1.6em;
+ display: block;
+ padding-left: 0.2em;
+}
+#leftnav a:link, #leftnav a:visited {
+ text-decoration: none;
+ color: #666666;
+}
+#leftnav a:hover {
+ background-color: #307fe1;
+ color: #ffffff;
+}
+
+
+#content {
+ max-width: 52em;
+ margin-left: 190px;
+ padding: 1em;
+ border-left: 1px solid #cccccc;
+ background-color: #ffffff;
+}
+
+#content ul {
+ list-style-image: url('bullet.gif');
+}
+
+#content a:link {
+ text-decoration: none;
+ color: #307fe1;
+}
+#content a:visited {
+ text-decoration: none;
+ color: #307fe1;
+}
+#content a:hover {
+ color: #307fe1;
+ text-decoration: underline;
+}
+
+#content h2 {
+ font-size: 150%;
+}
+#content h2:first-child {
+ margin: 0 0 0.5em;
+}
+
+
+.footer {
+ clear: both;
+ margin: 0;
+ padding: 0.5em;
+ background-color: #ffffff;
+ color: #333333;
+ text-align: center;
+ font-size: 90%;
+}
diff --git a/build/windows/launcher/processing.exe b/build/windows/launcher/processing.exe
new file mode 100755
index 000000000..0a8839d45
Binary files /dev/null and b/build/windows/launcher/processing.exe differ
diff --git a/build/windows/make.sh b/build/windows/make.sh
new file mode 100755
index 000000000..e7efec5f5
--- /dev/null
+++ b/build/windows/make.sh
@@ -0,0 +1,283 @@
+#!/bin/sh
+
+
+### -- SETUP WORK DIR -------------------------------------------
+
+if test -d work
+then
+ BUILD_PREPROC=false
+else
+ echo Setting up directories to build P5...
+ BUILD_PREPROC=true
+
+ mkdir work
+ cp -r ../shared/lib work/
+ cp -r ../shared/libraries work/
+ cp -r ../shared/tools work/
+
+ cp ../../app/lib/antlr.jar work/lib/
+ cp ../../app/lib/ecj.jar work/lib/
+ cp ../../app/lib/jna.jar work/lib/
+
+ echo Extracting examples...
+ unzip -q -d work/ ../shared/examples.zip
+
+ echo Extracting reference...
+ unzip -q -d work/ ../shared/reference.zip
+
+ cp -r ../../net work/libraries/
+ cp -r ../../opengl work/libraries/
+ cp -r ../../serial work/libraries/
+ cp -r ../../video work/libraries/
+ cp -r ../../pdf work/libraries/
+ cp -r ../../dxf work/libraries/
+
+ echo Extracting enormous JRE...
+ unzip -q -d work jre.zip
+
+ # build the export launcher
+ cd export
+ make
+ cd ..
+
+ # build the processing.exe bundle
+ # there are a few hacks in the source to launch4j-3.0.1
+ # to build them, use the following:
+ # cd head_src/gui_head && make -f Makefile.win
+ cd launcher
+ ./launch4j/launch4jc.exe config.xml
+ cp processing.exe ../work/
+ cd ..
+
+ # chmod +x the crew
+ # cygwin requires this because of unknown weirdness
+ # it was not formerly this anal retentive
+ # with the html, it's necessary on windows for launching reference
+ # from shell/command prompt, which is done internally to view reference
+ find work -name "*.html" -exec chmod +x {} ';'
+ find work -name "*.dll" -exec chmod +x {} ';'
+ find work -name "*.exe" -exec chmod +x {} ';'
+ find work -name "*.html" -exec chmod +x {} ';'
+fi
+
+cd ../..
+
+
+### -- BUILD CORE ----------------------------------------------
+
+echo Building processing.core...
+
+cd core
+
+#CLASSPATH="..\\build\\windows\\work\\java\\lib\\rt.jar;..\\build\\windows\\work\\java\\lib\\tools.jar"
+#CLASSPATH="..\\build\\windows\\work\\java\\lib\\tools.jar"
+#export CLASSPATH
+
+perl preproc.pl
+
+mkdir -p bin
+../build/windows/work/java/bin/java \
+ -classpath "..\\build\\windows\\work\\java\\lib\\tools.jar" \
+ com.sun.tools.javac.Main \
+ -source 1.5 -target 1.5 -d bin \
+ src/processing/core/*.java src/processing/xml/*.java
+
+rm -f ../build/windows/work/lib/core.jar
+
+# package this folder into core.jar
+cd bin && zip -rq ../../build/windows/work/lib/core.jar \
+ processing/core/*.class processing/xml/*.class && cd ..
+
+# back to base processing dir
+cd ..
+
+### -- BUILD PREPROC ---------------------------------------------
+
+if $BUILD_PREPROC
+then
+
+echo Building PDE for JDK 1.5
+
+cd app
+
+# first build the default java goop
+../build/windows/work/java/bin/java \
+ -cp "..\\build\\windows\\work\\lib\\antlr.jar" antlr.Tool \
+ -o src/antlr/java \
+ src/antlr/java/java.g
+
+# now build the pde stuff that extends the java classes
+#../../build/windows/work/java/bin/java \
+# -cp "..\\..\\build\\windows\\work\\lib\\antlr.jar" antlr.Tool \
+# -o src/processing/app/preproc \
+# -glib antlr/java/java.g processing/app/preproc/pde.g
+
+# this is totally ugly and needs to be fixed
+# the problem is that -glib doesn't set the main path properly,
+# so it's necessary to cd into the antlr/java folder, otherwise
+# the JavaTokenTypes.txt file won't be found
+
+# this is the eventual hack to make things work
+# why this is required on windows and not the others is beyond me
+cp src/antlr/java/JavaTokenTypes.txt src/processing/app/preproc/
+
+# this is a total disaster...fix me soon!
+cd src/processing/app/preproc
+../../../../../build/windows/work/java/bin/java \
+ -cp "..\\..\\..\\..\\..\\build\\windows\\work\\lib\\antlr.jar" antlr.Tool \
+ -glib ../../../antlr/java/java.g \
+ pde.g
+cd ../../../..
+
+
+# back to base processing dir
+cd ..
+
+fi
+
+
+### -- BUILD PDE ------------------------------------------------
+
+cd app
+
+# has to be present, otherwise javac will complain of file writing errors
+rm -rf ../build/windows/work/classes
+mkdir ../build/windows/work/classes
+
+../build/windows/work/java/bin/java \
+ -classpath "..\\build\\windows\\work\\java\\lib\\tools.jar" \
+ com.sun.tools.javac.Main \
+ -source 1.5 -target 1.5 \
+ -classpath "..\\build\\windows\\work\\lib\\core.jar;..\\build\\windows\\work\\lib\antlr.jar;..\\build\\windows\\work\\lib\\ecj.jar;..\\build\\windows\\work\\lib\\jna.jar;..\\build\\windows\\work\\java\\lib\\tools.jar" \
+ -d ..\\build\\windows\\work\\classes \
+ src/processing/app/*.java \
+ src/processing/app/debug/*.java \
+ src/processing/app/syntax/*.java \
+ src/processing/app/preproc/*.java \
+ src/processing/app/tools/*.java \
+ src/processing/app/windows/*.java \
+ src/antlr/*.java \
+ src/antlr/java/*.java
+
+cd ../build/windows/work/classes
+rm -f ../lib/pde.jar
+zip -rq ../lib/pde.jar .
+cd ../..
+
+
+### -- BUILD LIBRARIES ------------------------------------------------
+
+PLATFORM=windows
+
+
+#CLASSPATH="..\\build\\$PLATFORM\\work\\lib\\core.jar;..\\build\\$PLATFORM\\work\\java\\lib\\rt.jar"
+#CLASSPATH="..\\build\\$PLATFORM\\work\\lib\\core.jar"
+
+JAVAC="../build/windows/work/java/bin/java -classpath ..\\build\\windows\\work\\java\\lib\\tools.jar com.sun.tools.javac.Main -source 1.5 -target 1.5"
+CORE="..\\build\\$PLATFORM\\work\\lib\\core.jar"
+LIBRARIES="..\\build\\$PLATFORM\\work\\libraries"
+
+# move to processing/build
+cd ..
+
+
+# SERIAL LIBRARY
+echo Building serial library...
+cd ../serial
+mkdir -p bin
+$JAVAC \
+ -classpath "library\\RXTXcomm.jar;$CORE" \
+ -d bin src/processing/serial/*.java
+rm -f library/serial.jar
+find bin -name "*~" -exec rm -f {} ';'
+cd bin && zip -rq ../library/serial.jar processing/serial/*.class && cd ..
+mkdir -p $LIBRARIES/serial/library/
+cp library/serial.jar $LIBRARIES/serial/library/
+
+# NET LIBRARY
+echo Building net library...
+cd ../net
+mkdir -p bin
+$JAVAC \
+ -classpath "$CORE" \
+ -d bin src/processing/net/*.java
+rm -f library/net.jar
+find bin -name "*~" -exec rm -f {} ';'
+cd bin && zip -rq ../library/net.jar processing/net/*.class && cd ..
+mkdir -p $LIBRARIES/net/library/
+cp library/net.jar $LIBRARIES/net/library/
+
+
+# VIDEO LIBRARY
+echo Building video library...
+if test -f "${QTJAVA}"
+then
+ echo "Found Quicktime 7 installation"
+else
+ QTJAVA="$WINDIR\\system32\\QTJava.zip"
+ if test -f "${QTJAVA}"
+ then
+ echo "Found Quicktime 6 at $QTJAVA"
+ else
+ echo "Could not find QuickTime for Java,"
+ echo "you'll need to install it before building."
+ exit 1;
+ fi
+fi
+cd ../video
+mkdir -p bin
+$JAVAC \
+ -classpath "$QTJAVA;$CORE" \
+ -d bin src/processing/video/*.java
+rm -f library/video.jar
+find bin -name "*~" -exec rm -f {} ';'
+cd bin && zip -rq ../library/video.jar processing/video/*.class && cd ..
+mkdir -p $LIBRARIES/video/library/
+cp library/video.jar $LIBRARIES/video/library/
+
+
+# OPENGL LIBRARY
+echo Building OpenGL library...
+cd ../opengl
+mkdir -p bin
+$JAVAC \
+ -classpath "library\\jogl.jar;$CORE" \
+ -d bin src/processing/opengl/*.java
+rm -f library/opengl.jar
+find bin -name "*~" -exec rm -f {} ';'
+cd bin && zip -rq ../library/opengl.jar processing/opengl/*.class && cd ..
+mkdir -p $LIBRARIES/opengl/library/
+cp library/opengl.jar $LIBRARIES/opengl/library/
+
+
+# PDF LIBRARY
+echo Building PDF library...
+cd ../pdf
+mkdir -p bin
+$JAVAC \
+ -classpath "library\\itext.jar;$CORE" \
+ -d bin src/processing/pdf/*.java
+rm -f library/pdf.jar
+find bin -name "*~" -exec rm -f {} ';'
+cd bin && zip -rq ../library/pdf.jar processing/pdf/*.class && cd ..
+mkdir -p $LIBRARIES/pdf/library/
+cp library/pdf.jar $LIBRARIES/pdf/library/
+
+
+# DXF LIBRARY
+echo Building DXF library...
+cd ../dxf
+mkdir -p bin
+$JAVAC \
+ -classpath "$CORE" \
+ -d bin src/processing/dxf/*.java
+rm -f library/dxf.jar
+find bin -name "*~" -exec rm -f {} ';'
+cd bin && zip -rq ../library/dxf.jar processing/dxf/*.class && cd ..
+mkdir -p $LIBRARIES/dxf/library/
+cp library/dxf.jar $LIBRARIES/dxf/library/
+
+
+echo
+echo Done.
+
diff --git a/build/windows/run.sh b/build/windows/run.sh
new file mode 100644
index 000000000..f02bbbdff
--- /dev/null
+++ b/build/windows/run.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+CLASSPATH=lib\\pde.jar\;lib\\core.jar\;lib\\jna.jar\;lib\\ecj.jar\;lib\\antlr.jar\;java\\lib\\tools.jar
+export CLASSPATH
+
+cd work && ./java/bin/java processing.app.Base
diff --git a/build/windows/srun.sh b/build/windows/srun.sh
new file mode 100755
index 000000000..d81943ba9
--- /dev/null
+++ b/build/windows/srun.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+QT_JAVA_PATH="$WINDIR\\system32\\QTJava.zip"
+if test -f "${QT_JAVA_PATH}"
+then
+ #echo "Found Quicktime at $QT_JAVA_PATH"
+else
+ QT_JAVA_PATH="$WINDIR\\system\\QTJava.zip"
+ if test -f "${QT_JAVA_PATH}"
+ echo "could not find qtjava.zip in either"
+ echo "${WINDIR}\\system32\\qtjava.zip or"
+ echo "${WINDIR}\\system\\qtjava.zip"
+ echo "quicktime for java must be installed before building."
+ exit 1;
+ then
+ #echo "Found Quicktime at $QT_JAVA_PATH"
+ else
+ fi
+fi
+
+CLASSPATH=\"java\\lib\\rt.jar\;lib\;lib\\build\;lib\\pde.jar\;lib\\kjc.jar\;lib\\antlr.jar\;lib\\oro.jar\;lib\\comm.jar\;lib\\RXTXcomm.jar\;${QT_JAVA_PATH}\"
+
+export CLASSPATH
+
+cd work && ./java/bin/java -Djava.compiler=NONE PdeBase
diff --git a/core/.classpath b/core/.classpath
new file mode 100644
index 000000000..fb5011632
--- /dev/null
+++ b/core/.classpath
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/core/.project b/core/.project
new file mode 100644
index 000000000..9884df8b9
--- /dev/null
+++ b/core/.project
@@ -0,0 +1,17 @@
+
+
+ core
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/core/.settings/org.eclipse.jdt.core.prefs b/core/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 000000000..f80f9b559
--- /dev/null
+++ b/core/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,261 @@
+#Thu Aug 28 17:36:28 EDT 2008
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
+org.eclipse.jdt.core.compiler.compliance=1.5
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.5
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+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=18
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=82
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+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_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.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=true
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
+org.eclipse.jdt.core.formatter.comment.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.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+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_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_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_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_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_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_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.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=false
+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_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
diff --git a/core/.settings/org.eclipse.jdt.ui.prefs b/core/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 000000000..cfbda4c3e
--- /dev/null
+++ b/core/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,5 @@
+#Thu Jan 10 10:50:38 PST 2008
+eclipse.preferences.version=1
+formatter_profile=_two spaces no tabs
+formatter_settings_version=11
+org.eclipse.jdt.ui.text.custom_code_templates=
diff --git a/core/api.txt b/core/api.txt
new file mode 100644
index 000000000..4b2746f8b
--- /dev/null
+++ b/core/api.txt
@@ -0,0 +1,413 @@
+
+ public void setParent(PApplet parent)
+ public void setPrimary(boolean primary)
+ public void setPath(String path)
+ public void setSize(int iwidth, int iheight)
+ protected void allocate()
+ public void dispose()
+
+ public boolean canDraw()
+ public void beginDraw()
+ public void endDraw()
+
+ protected void checkSettings()
+ protected void defaultSettings()
+ protected void reapplySettings()
+
+ public void hint(int which)
+
+ public void beginShape()
+ public void beginShape(int kind)
+ public void edge(boolean e)
+ public void normal(float nx, float ny, float nz)
+ public void textureMode(int mode)
+ public void texture(PImage image)
+ public void vertex(float x, float y)
+ public void vertex(float x, float y, float z)
+ public void vertex(float x, float y, float u, float v)
+ public void vertex(float x, float y, float z, float u, float v)
+ protected void vertexTexture(float u, float v);
+ public void breakShape()
+ public void endShape()
+ public void endShape(int mode)
+
+ protected void bezierVertexCheck();
+ public void bezierVertex(float x2, float y2,
+ float x3, float y3,
+ float x4, float y4)
+ public void bezierVertex(float x2, float y2, float z2,
+ float x3, float y3, float z3,
+ float x4, float y4, float z4)
+
+ protected void curveVertexCheck();
+ public void curveVertex(float x, float y)
+ public void curveVertex(float x, float y, float z)
+ protected void curveVertexSegment(float x1, float y1,
+ float x2, float y2,
+ float x3, float y3,
+ float x4, float y4)
+ protected void curveVertexSegment(float x1, float y1, float z1,
+ float x2, float y2, float z2,
+ float x3, float y3, float z3,
+ float x4, float y4, float z4)
+
+ protected void renderPoints(int start, int stop) // P3D
+ protected void rawPoints(int start, int stop) // P3D
+
+ protected void renderLines(int start, int stop) // P3D
+ protected void rawLines(int start, int stop) // P3D
+
+ protected void renderTriangles(int start, int stop) // P3D
+ protected void rawTriangles(int start, int stop) // P3D
+
+ public void flush()
+ protected void render()
+ proected void sort()
+
+ public void point(float x, float y)
+ public void point(float x, float y, float z)
+ public void line(float x1, float y1, float x2, float y2)
+ public void line(float x1, float y1, float z1,
+ float x2, float y2, float z2)
+ public void triangle(float x1, float y1,
+ float x2, float y2,
+ float x3, float y3)
+ public void quad(float x1, float y1, float x2, float y2,
+ float x3, float y3, float x4, float y4)
+
+ public void rectMode(int mode)
+ public void rect(float a, float b, float c, float d)
+ protected void rectImpl(float x1, float y1, float x2, float y2)
+
+ public void ellipseMode(int mode)
+ public void ellipse(float a, float b, float c, float d)
+ protected void ellipseImpl(float x, float y, float w, float h)
+
+ public void arc(float a, float b, float c, float d,
+ float start, float stop)
+ protected void arcImpl(float x, float y, float w, float h,
+ float start, float stop)
+
+ public void box(float size)
+ public void box(float w, float h, float d)
+
+ public void sphereDetail(int res)
+ public void sphereDetail(int ures, int vres)
+ public void sphere(float r)
+
+ public float bezierPoint(float a, float b, float c, float d, float t)
+ public float bezierTangent(float a, float b, float c, float d, float t)
+ protected void bezierInitCheck()
+ protected void bezierInit()
+ public void bezierDetail(int detail)
+ public void bezier(float x1, float y1,
+ float x2, float y2,
+ float x3, float y3,
+ float x4, float y4)
+ public void bezier(float x1, float y1, float z1,
+ float x2, float y2, float z2,
+ float x3, float y3, float z3,
+ float x4, float y4, float z4)
+
+ public float curvePoint(float a, float b, float c, float d, float t)
+ public float curveTangent(float a, float b, float c, float d, float t)
+ public void curveDetail(int detail)
+ public void curveTightness(float tightness)
+ protected void curveInitCheck()
+ protected void curveInit()
+ public void curve(float x1, float y1,
+ float x2, float y2,
+ float x3, float y3,
+ float x4, float y4)
+ public void curve(float x1, float y1, float z1,
+ float x2, float y2, float z2,
+ float x3, float y3, float z3,
+ float x4, float y4, float z4)
+
+ protected void splineForward(int segments, PMatrix3D matrix)
+
+ public void smooth()
+ public void noSmooth()
+
+ public void imageMode(int mode)
+ public void image(PImage image, float x, float y)
+ public void image(PImage image, float x, float y, float c, float d)
+ public void image(PImage image,
+ float a, float b, float c, float d,
+ int u1, int v1, int u2, int v2)
+ protected void imageImpl(PImage image,
+ float x1, float y1, float x2, float y2,
+ int u1, int v1, int u2, int v2)
+
+ public void shapeMode(int mode)
+ public void shape(PShape shape)
+ public void shape(PShape shape, float x, float y)
+ public void shape(PShape shape, float x, float y, float c, float d)
+
+ public void textAlign(int align)
+ public void textAlign(int alignX, int alignY)
+ public float textAscent()
+ public float textDescent()
+ public void textFont(PFont which)
+ public void textFont(PFont which, float size)
+ public void textLeading(float leading)
+ public void textMode(int mode)
+ protected boolean textModeCheck(int mode)
+ public void textSize(float size)
+ public float textWidth(char c)
+ public float textWidth(String str)
+ protected float textWidthImpl(char buffer[], int start, int stop)
+
+ public void text(char c)
+ public void text(char c, float x, float y)
+ public void text(char c, float x, float y, float z)
+ public void text(String str)
+ public void text(String str, float x, float y)
+ public void text(String str, float x, float y, float z)
+ public void text(String str, float x1, float y1, float x2, float y2)
+ public void text(String s, float x1, float y1, float x2, float y2, float z)
+ public void text(int num, float x, float y)
+ public void text(int num, float x, float y, float z)
+ public void text(float num, float x, float y)
+ public void text(float num, float x, float y, float z)
+
+ protected void textLineAlignImpl(char buffer[], int start, int stop,
+ float x, float y)
+ protected void textLineImpl(char buffer[], int start, int stop,
+ float x, float y)
+ protected void textCharImpl(char ch, float x, float y)
+ protected void textCharModelImpl(PImage glyph,
+ float x1, float y1, //float z1,
+ float x2, float y2, //float z2,
+ int u2, int v2)
+ protected void textCharScreenImpl(PImage glyph,
+ int xx, int yy,
+ int w0, int h0)
+
+ public void pushMatrix()
+ public void popMatrix()
+
+ public void translate(float tx, float ty)
+ public void translate(float tx, float ty, float tz)
+ public void rotate(float angle)
+ public void rotateX(float angle)
+ public void rotateY(float angle)
+ public void rotateZ(float angle)
+ public void rotate(float angle, float vx, float vy, float vz)
+ public void scale(float s)
+ public void scale(float sx, float sy)
+ public void scale(float x, float y, float z)
+
+ public void resetMatrix()
+ public void applyMatrix(PMatrix2D source)
+ public void applyMatrix(float n00, float n01, float n02,
+ float n10, float n11, float n12)
+ public void applyMatrix(PMatrix3D source)
+ public void applyMatrix(float n00, float n01, float n02, float n03,
+ float n10, float n11, float n12, float n13,
+ float n20, float n21, float n22, float n23,
+ float n30, float n31, float n32, float n33)
+
+ public getMatrix(PMatrix2D target)
+ public getMatrix(PMatrix3D target)
+ public void setMatrix(PMatrix2D source)
+ public void setMatrix(PMatrix3D source)
+ public void printMatrix()
+
+ public void beginCamera()
+ public void endCamera()
+ public void camera()
+ public void camera(float eyeX, float eyeY, float eyeZ,
+ float centerX, float centerY, float centerZ,
+ float upX, float upY, float upZ)
+ public void printCamera()
+
+ public void ortho()
+ public void ortho(float left, float right,
+ float bottom, float top,
+ float near, float far)
+ public void perspective()
+ public void perspective(float fov, float aspect, float near, float far)
+ public void frustum(float left, float right,
+ float bottom, float top,
+ float near, float far)
+ public void printProjection()
+
+ public float screenX(float x, float y)
+ public float screenY(float x, float y)
+ public float screenX(float x, float y, float z)
+ public float screenY(float x, float y, float z)
+ public float screenZ(float x, float y, float z)
+ public float modelX(float x, float y, float z)
+ public float modelY(float x, float y, float z)
+ public float modelZ(float x, float y, float z)
+
+ public void pushStyle()
+ public void popStyle()
+ public void style(PStyle)
+ public PStyle getStyle()
+ public void getStyle(PStyle)
+
+ public void strokeCap(int cap)
+ public void strokeJoin(int join)
+ public void strokeWeight(float weight)
+
+ public void noStroke()
+ public void stroke(int rgb)
+ public void stroke(int rgb, float alpha)
+ public void stroke(float gray)
+ public void stroke(float gray, float alpha)
+ public void stroke(float x, float y, float z)
+ public void stroke(float x, float y, float z, float a)
+ protected void strokeFromCalc()
+
+ public void noTint()
+ public void tint(int rgb)
+ public void tint(int rgb, float alpha)
+ public void tint(float gray)
+ public void tint(float gray, float alpha)
+ public void tint(float x, float y, float z)
+ public void tint(float x, float y, float z, float a)
+ protected void tintFromCalc()
+
+ public void noFill()
+ public void fill(int rgb)
+ public void fill(int rgb, float alpha)
+ public void fill(float gray)
+ public void fill(float gray, float alpha)
+ public void fill(float x, float y, float z)
+ public void fill(float x, float y, float z, float a)
+ protected void fillFromCalc()
+
+ public void ambient(int rgb)
+ public void ambient(float gray)
+ public void ambient(float x, float y, float z)
+ protected void ambientFromCalc()
+ public void specular(int rgb)
+ public void specular(float gray)
+ public void specular(float x, float y, float z)
+ protected void specularFromCalc()
+ public void shininess(float shine)
+ public void emissive(int rgb)
+ public void emissive(float gray)
+ public void emissive(float x, float y, float z )
+ protected void emissiveFromCalc()
+
+ public void lights()
+ public void noLights()
+ public void ambientLight(float red, float green, float blue)
+ public void ambientLight(float red, float green, float blue,
+ float x, float y, float z)
+ public void directionalLight(float red, float green, float blue,
+ float nx, float ny, float nz)
+ public void pointLight(float red, float green, float blue,
+ float x, float y, float z)
+ public void spotLight(float red, float green, float blue,
+ float x, float y, float z,
+ float nx, float ny, float nz,
+ float angle, float concentration)
+ public void lightFalloff(float constant, float linear, float quadratic)
+ public void lightSpecular(float x, float y, float z)
+ protected void lightPosition(int num, float x, float y, float z)
+ protected void lightDirection(int num, float x, float y, float z)
+
+ public void background(int rgb)
+ public void background(int rgb, float alpha)
+ public void background(float gray)
+ public void background(float gray, float alpha)
+ public void background(float x, float y, float z)
+ public void background(float x, float y, float z, float a)
+ public void background(PImage image)
+ protected void backgroundFromCalc()
+ protected void backgroundImpl(PImage image)
+ protected void backgroundImpl()
+
+ public void colorMode(int mode)
+ public void colorMode(int mode, float max)
+ public void colorMode(int mode, float maxX, float maxY, float maxZ)
+ public void colorMode(int mode, float maxX, float maxY, float maxZ, float maxA)
+
+ protected void colorCalc(int rgb)
+ protected void colorCalc(int rgb, float alpha)
+ protected void colorCalc(float gray)
+ protected void colorCalc(float gray, float alpha)
+ protected void colorCalc(float x, float y, float z)
+ protected void colorCalc(float x, float y, float z, float a)
+ protected void colorCalcARGB(int argb, float alpha)
+
+ public final int color(int gray)
+ public final int color(int gray, int alpha)
+ public final int color(int rgb, float alpha)
+ public final int color(int x, int y, int z)
+
+ public final float alpha(int what)
+ public final float red(int what)
+ public final float green(int what)
+ public final float blue(int what)
+ public final float hue(int what)
+ public final float saturation(int what)
+ public final float brightness(int what)
+
+ public int lerpColor(int c1, int c2, float amt)
+ static public int lerpColor(int c1, int c2, float amt, int mode)
+
+ public void beginRaw(PGraphics rawGraphics)
+ public void endRaw()
+
+ static public void showWarning(String msg)
+ static public void showException(String msg)
+
+ public boolean displayable()
+ public boolean is2D()
+ public boolean is3D()
+
+//
+
+These are the methods found in PImage, which are inherited by PGraphics.
+
+ public PImage(Image)
+ public Image getImage()
+
+ public void setCache(Object parent, Object storage)
+ public void getCache(Object parent)
+ public void removeCache(Object parent)
+
+ public boolean isModified();
+ public void setModified();
+ public void setModified(boolean state);
+
+ public void loadPixels()
+ public void updatePixels()
+ public void updatePixels(int x, int y, int w, int h)
+
+ public void resize(int wide, int high)
+
+ public int get(int x, int y)
+ public PImage get(int x, int y, int w, int h)
+ protected PImage getImpl(int x, int y, int w, int h)
+ public PImage get()
+ public void set(int x, int y, int c)
+ public void set(int x, int y, PImage src)
+ protected void setImpl(int dx, int dy, int sx, int sy, int sw, int sh,
+ PImage src)
+
+ public void mask(int alpha[])
+ public void mask(PImage alpha)
+
+ public void filter(int kind)
+ public void filter(int kind, float param)
+
+ public void copy(int sx, int sy, int sw, int sh,
+ int dx, int dy, int dw, int dh)
+ public void copy(PImage src,
+ int sx, int sy, int sw, int sh,
+ int dx, int dy, int dw, int dh)
+
+ static public int blendColor(int c1, int c2, int mode)
+ public void blend(int sx, int sy, int sw, int sh,
+ int dx, int dy, int dw, int dh, int mode)
+ public void blend(PImage src,
+ int sx, int sy, int sw, int sh,
+ int dx, int dy, int dw, int dh, int mode)
+
+ public void save(String path)
diff --git a/core/done.txt b/core/done.txt
new file mode 100644
index 000000000..e2eb2ec90
--- /dev/null
+++ b/core/done.txt
@@ -0,0 +1,2878 @@
+0164 core (1.0.2)
+X requestImage() causing problems with JAVA2D
+X fix minor strokeWeight bug with OpenGL
+X text() with char array
+o add documentation
+o add this for text in a rectangle?
+X minor bug fix to svg files that weren't being resized properly
+X OpenGL is rendering darker in 0149+
+X http://dev.processing.org/bugs/show_bug.cgi?id=958
+X the fix has been found, just incorporate it
+X thanks to dave bollinger
+X OutOfMemoryError with ellipse() in P3D and OPENGL
+X http://dev.processing.org/bugs/show_bug.cgi?id=1086
+X should also fix problem with AIOOBE
+X http://dev.processing.org/bugs/show_bug.cgi?id=1117
+X point(x,y) ignores noStroke() (in some renderers)
+X http://dev.processing.org/bugs/show_bug.cgi?id=1090
+X fix startup problem when scheme coloring was odd
+X http://dev.processing.org/bugs/show_bug.cgi?id=1109
+X fix several point() problems with P3D
+X http://dev.processing.org/bugs/show_bug.cgi?id=1110
+X nextPage() not working properly with PDF as the renderer
+X http://dev.processing.org/bugs/show_bug.cgi?id=1131
+X save styles when nextPage() is called
+X beginRaw() broken (no DXF, etc working)
+X http://dev.processing.org/bugs/show_bug.cgi?id=1099
+X http://dev.processing.org/bugs/show_bug.cgi?id=1144
+X Fix algorithm for quadratic to cubic curve conversion
+X wrong algorithm in PGraphicsOpenGL and PShapeSVG
+X (thanks to user 'shambles')
+X http://dev.processing.org/bugs/show_bug.cgi?id=1122
+X tint() not working in P2D
+X http://dev.processing.org/bugs/show_bug.cgi?id=1132
+X blend() y coordinates inverted when using OpenGL
+X http://dev.processing.org/bugs/show_bug.cgi?id=1137
+
+invalid/wontfix/dupe
+X Processing will not start with non-standard disk partitioning on OS X
+X http://dev.processing.org/bugs/show_bug.cgi?id=1127
+X Got NoClassDefFoundError exception when accessing quicktime API
+X http://dev.processing.org/bugs/show_bug.cgi?id=1128
+X http://dev.processing.org/bugs/show_bug.cgi?id=1129
+X http://dev.processing.org/bugs/show_bug.cgi?id=1130
+X not using present mode correctly
+X http://dev.processing.org/bugs/show_bug.cgi?id=1138
+X apparent graphics driver conflict on vista
+X http://dev.processing.org/bugs/show_bug.cgi?id=1140
+X PImage.save() does not create parent directories
+X http://dev.processing.org/bugs/show_bug.cgi?id=1124
+X sketch turning blue and not working on osx
+X http://dev.processing.org/bugs/show_bug.cgi?id=1164
+X dupe: blend() inaccurary
+X http://dev.processing.org/bugs/show_bug.cgi?id=1008
+X glPushAttrib style function
+X http://dev.processing.org/bugs/show_bug.cgi?id=1150
+X calling saveFrame() in noLoop() (update reference)
+X http://dev.processing.org/bugs/show_bug.cgi?id=1155
+
+xml
+X fix for xml elements that have null names
+X added listChildren() method
+X added optional toString(boolean) parameter to enable/disable indents
+
+
+0163 core (1.0.1)
+X do not parse split() with regexp
+X http://dev.processing.org/bugs/show_bug.cgi?id=1060
+X ArrayIndexOutOfBoundsException in ellipseImpl() with 1.0
+X http://dev.processing.org/bugs/show_bug.cgi?id=1068
+
+
+0162 core (1.0)
+X no additional changes for 1.0
+
+
+0161 core
+X present on macosx causing strange flicker/jump while window opens
+X using validate() for present mode, pack() otherwise
+X http://dev.processing.org/bugs/show_bug.cgi?id=1051
+
+
+0160 core
+X stroked lines drawing on top of everything else in P3D
+X http://dev.processing.org/bugs/show_bug.cgi?id=1032
+X 100x100 sketches not working
+
+
+0159 core
+o disable present mode? (weirdness with placements on mac)
+X deal with some present mode issues
+X use FSE on mac within the PDE
+X when exporting, never use FSE
+_ document changes re: can specify --exclusive on command line
+X do we need to do glEnable for multisample with gl?
+o just need to test this on a few platforms
+X doesn't seem to be the case
+X Present mode and OPENGL not working in 0156 with Windows Vista
+X http://dev.processing.org/bugs/show_bug.cgi?id=1009
+X Seems to be limited to Java 6u10 (but verify)
+o -Dsun.java2d.d3d=false seems to fix the problem
+o can probably add that to PApplet.main()
+X does not work
+
+
+0158 core
+X beginShape(TRIANGLE_FAN), and therefore arc(), broken in P2D
+X also a typo in the ColorWheel example
+X http://dev.processing.org/bugs/show_bug.cgi?id=1019
+X P2D - null pointer exception drawing line with alpha stroke
+X http://dev.processing.org/bugs/show_bug.cgi?id=1023
+X P2D endShape() is working like endShape(CLOSE)
+X http://dev.processing.org/bugs/show_bug.cgi?id=1021
+X http://dev.processing.org/bugs/show_bug.cgi?id=1028 (mark as dupe)
+X arc() center transparent
+X http://dev.processing.org/bugs/show_bug.cgi?id=1027
+X mark as dupe of bug #200
+X but fixed for the P2D case, still afflicts P2D
+X P2D - alpha stroke rendered at full opacity
+X http://dev.processing.org/bugs/show_bug.cgi?id=1024
+X smooth() on single line ellipses not coming out smooth
+X sort of works, just not great
+X improve (slightly) the quality of ellipse() and arc() with P2D
+X don't use TRIANGLE_FAN on ellipseImpl() and arcImpl() with P2D
+X split out ellipseImpl and arcImpl from PGraphics into P2D and P3D
+X figure out better model for adaptive sizing of circles
+X also goes for arcs, though will be weighted based on arc size
+X Bring back CENTER_RADIUS but deprecate it
+X http://dev.processing.org/bugs/show_bug.cgi?id=1035
+X enable smoothing by default in opengl
+X change hints to instead only be able to DISABLE 2X or 4X
+X bring back .width and .height fields for PShape
+o need to update the examples to reflect
+X no examples to update
+X change reference re: smoothing in opengl
+X hint(), smooth(), and size()
+X rev the version number
+
+
+0157 core
+X SVG polygon shapes not drawing since loadShape() and PShape changes
+X http://dev.processing.org/bugs/show_bug.cgi?id=1005
+X image(a, x, y) not honoring imageMode(CENTER)
+X need to just pass image(a, x, y) to image(a, x, y, a.width, a.height)
+X rather than passing it directly to imageImpl()
+X http://dev.processing.org/bugs/show_bug.cgi?id=1013
+o disable P2D before releasing (unless implementation is finished)
+
+
+0156 core
+X clarify the "no variables in size() command" rule
+X http://dev.processing.org/bugs/show_bug.cgi?id=992
+X present mode broken in general?
+X placement of elements in present mode is messed up
+X "stop" button hops around, window not centered on screen
+X http://dev.processing.org/bugs/show_bug.cgi?id=923
+X disable P2D for size() and createGraphics() before releasing
+X already was disabled, just a bug in detecting it
+
+
+0155 core
+X hint(DISABLE_DEPTH_TEST) throws null pointer exception with OpenGL
+X http://dev.processing.org/bugs/show_bug.cgi?id=984
+
+
+0154 core
+X only set apple.awt.graphics.UseQuartz on osx, otherwise security error
+X http://dev.processing.org/bugs/show_bug.cgi?id=976
+X add skewX() and skewY() to PMatrix
+X Add support style attribute for path tag to Candy SVG (ricard)
+X http://dev.processing.org/bugs/show_bug.cgi?id=771
+X remove setX/Y/Z from PVector, copy() (use get() instead), add mult/div
+X remove copy() from PVector?
+X add mult() and div() with vector inputs?
+
+
+0153 core
+X make PImage.init() public again
+
+
+0152 core
+X no changes to 0152 core
+
+
+0151 core
+X NullPointerException on curveVertex() when using more than 128 vertices
+X http://dev.processing.org/bugs/show_bug.cgi?id=952
+X Text not bounding correctly with x, y, w, h
+X http://dev.processing.org/bugs/show_bug.cgi?id=954
+o dataFolder() might be flawed b/c it's referring to contents of jar file
+o for input, better to use openStream
+X clear up the javadoc on this
+X odd-size height will make blue line across image in saveFrame()
+X http://dev.processing.org/bugs/show_bug.cgi?id=944
+X probably the pixel flipping code (and endian sorting) not happening
+X because the blue comes from the byte order flip
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=OpenGL;action=post;num=1219196429
+X ArrayIndexOutOfBoundsException in PLine
+X http://dev.processing.org/bugs/show_bug.cgi?id=246
+X http://dev.processing.org/bugs/show_bug.cgi?id=462
+X random AIOOBE with P3D and points
+X http://dev.processing.org/bugs/show_bug.cgi?id=937
+
+cleanup
+X alter bezier and curve matrices to use PMatrix
+X float array stuff is redundant with code that's in PMatrix
+X and PMatrix has to be included even w/o P3D so...
+X add texture support to begin/endRaw
+X should we do joins when alpha is turned off?
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=OpenGL;action=display;num=1210007450
+X no, because it's too processor intensive to draw a lotta ellipses
+X but added a note about it to the reference for 0151
+X strokeWeight() doesn't work in opengl or p3d
+o gl smoothing.. how to disable polygon but keep line enabled
+o or at least make a note of this?
+o leave smooth off, get the gl object, then enable line smooth
+X don't bother, this is a workaround for another bug
+o PPolygon no longer in use and PLine is a mess
+o make a version of PGraphics3 that uses it for more accurate rendering?
+
+
+0150 core
+X no changes to processing.core in 0150
+
+
+0149 core
+X remove MACOS9 constant from processing.core.*
+X because code no longer runs on os9 since dropping 1.1 support
+X specular() with alpha has been removed
+X GLDrawableFactory.chooseGraphicsConfiguration() error with OpenGL
+X http://dev.processing.org/bugs/show_bug.cgi?id=891
+X http://dev.processing.org/bugs/show_bug.cgi?id=908
+X fix problem with unregisterXxxx()
+X http://dev.processing.org/bugs/show_bug.cgi?id=910
+X make parseFloat() with String[] array return NaN for missing values
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Syntax;action=display;num=1220880375
+X fix problems with text in a rectangle
+X http://dev.processing.org/bugs/show_bug.cgi?id=893
+X http://dev.processing.org/bugs/show_bug.cgi?id=899
+X finish getImage() method inside PImage
+X delay() is broken
+X http://dev.processing.org/bugs/show_bug.cgi?id=894
+X remove extra ~ files from core.jar
+X also fix for other libraries in the make scripts across platforms
+X fix problems in PApplet regarding signed code
+X createInput() wasn't bothering to check files when not online
+X unhint() has been removed, see the reference for hint() for changes
+o enable() and disable() instead of hint()/unhint()
+o should these use text strings? how will that be compiled?
+X remove unhint(), add opposite hints for those that need to be disabled
+o maybe update hint() ref to be more clear about screen not accumulating
+X no, it's explicitly stated as such
+X make decisions about whether PGraphics is an abstract class or not
+X method signature is a real problem
+X figure out how to handle constructor mess
+X clean up setMainDrawingSurface()
+X should instead be inside size(), and init(), no?
+X add to hint(DISABLE_DEPTH_TEST)
+X gl.glClear(GL.GL_DEPTH_BUFFER_BIT);
+X or clearing the zbuffer for P3D
+X also add a note to the hint() reference
+X DISABLE_DEPTH_TEST bad results
+X have to clear the zbuffer to make it work
+X this may be specific to lines
+X http://dev.processing.org/bugs/show_bug.cgi?id=827
+X though it also seems to be a problem with opengl
+X also make a note of disabling as a way to help font appearance
+o Font width calculation fails when using vectorfonts and PDF
+o http://dev.processing.org/bugs/show_bug.cgi?id=920
+X um, this is gross: getMatrix((PMatrix2D) null)
+X no changing point sizes when using beginShape(POINTS)
+X this is an opengl restriction, should we stick with it elsewhere?
+X and changing stroke weight in general (with lines/shapes)
+o no renderer does this, we should probably disable it
+X added a note to the reference about it
+X may need to add to PApplet.main() for OS X 10.5
+X System.setProperty("apple.awt.graphics.UseQuartz", "true");
+X deprecate arraycopy(), change to arrayCopy()
+
+cleaning
+o chooseFile() and chooseFolder() with named fxn callbacks
+o the function must take a File object as a parameter
+o add better error messages for all built-in renderers
+o i.e. "import library -> pdf" when pdf is missing
+o cameraXYZ doesn't seem to actually be used for anything
+o since camera functions don't even look at it or set it
+o registerSize() in arcball is causing trouble
+o some sort of infinite loop issue
+o textMode(SCREEN) is broken for opengl
+o http://dev.processing.org/bugs/show_bug.cgi?id=426
+o textSpace(SCREEN) for opengl and java2d
+o don't use loadPixels for either
+o use font code to set the cached color of the font, then call set()
+o although set() with alpha is a little different..
+o resizing opengl applet likely to cause big trouble
+o componentlistener should prolly only do size() command outside of draw
+o fjen says blend() doens't work in JAVA2D
+o the functions are fairly well separated now in PMethods
+o just go through all the stuff to make sure it's setting properly
+
+point()
+X java2d - if strokeWeight is 1, do screenX/Y and set()
+X if strokeWeight larger, should work ok with line()
+X no, use an ellipse if strokeWeight is larger
+X gl points not working again
+X need to implement point() as actual gl points
+X this means adding points to the pipeline
+X point() doesn't work with some graphics card setups
+X particularly with opengl and java2d
+X http://dev.processing.org/bugs/show_bug.cgi?id=121
+X point() issues
+o point() being funneled through beginShape is terribly slow
+X go the other way 'round
+X sometimes broken, could be a problem with java 1.5? (was using win2k)
+
+font
+X fix getFontMetrics() warning
+X need to have a getGraphics() to get the actual Graphics object
+X where drawing is happening. parent.getGraphics() works except for OpenGL
+X Java2D textLinePlacedImpl should check for ENABLE_NATIVE_FONTS hint
+X http://dev.processing.org/bugs/show_bug.cgi?id=633
+X also try to check native font on textFont() commands
+X in case the hint() has been enabled in the meantime
+X or rather, always load native font, even w/o the hint() being set
+
+PGraphics API changes
+X setMainDrawingSurface() -> setPrimarySurface()
+X mainDrawingSurface = primarySurface;
+X resize() -> setSize() (roughly)
+X endShape() with no params is no longer 'final'
+X X/Y/Z -> TX/TY/TZ
+X MX/MY/MZ -> X/Y/Z (for sake of PShape)
+X render_triangles -> renderTriangles()
+X depth_sort_triangles -> sortTriangles()
+X render_lines -> renderLines()
+X depth_sort_lines -> sortLines()
+X no longer any abstract methods in PGraphics itself
+X removed support for specular alpha (and its 'SPA' constant)
+X clear() -> backgroundImpl()
+X add DIAMETER as synonym for CENTER for ellipseMode and friends
+X textFontNative and textFontNativeMetrics have been removed
+X they've been re-implemented per-PGraphics in a less hacky way
+X hint(ENABLE_NATIVE_FONTS) goes away
+X need to mention in createFont() reference
+X also maybe cover in the loadFont() reference? (maybe problem...)
+X image.cache has been removed, replaced with get/set/removeCache()
+X this allows per-renderer image cache data to be stored
+X imageMode has been removed from PImage, too awkward
+X this also means that imageMode ignored for get(), set(), blend() and copy()
+X smooth is now part of PGraphics, moved out of PImage
+X raw must handle points, lines, triangles, and textures
+X light position and normal are now PVector object
+X changed NORMALIZED to NORMAL for textureMode()
+
+shapes
+X maybe finish off the svg crap for this release
+X working on pshape
+X add shape() methods to PGraphics/PApplet
+X test and fix svg examples
+X revisions.txt for x/y/z/ tx/ty/tz.. other changes in api.txt
+X bring svg into main lib
+X need to straighten out 'table' object for quick object lookup
+X maybe add to all parent tables? (no, this gets enormous quickly)
+X fix svg caps/joins for opengl with svg library
+X http://dev.processing.org/bugs/show_bug.cgi?id=628
+X save/restore more of the p5 graphics drawing state
+X not setting colorMode(), strokeCap, etc.
+X ignoreStyles is broken - how to handle
+X need a whole "styles" handler
+X handle cap/join stuff by
+X if it's setting the default, no error message
+X if it's not the default, then show an error msg once
+X have a list Strings for errors called, rather than constants for all
+X that way, no need to have an error message for every friggin function
+X PMatrix now PMatrix3D (maybe not yet?)
+X change svg library reference
+
+hint/unhint/enable/disable
+X option to have renderer errors show up
+X 1) as text warnings 2) as runtime exceptions 3) never
+X add warning system for pgraphics, rather than runtime exceptions
+X keep array of warning strings, and booleans for whether they've called
+X ENABLE_DEPTH_SORT not really working for GL
+X because the zbuffer is still there, it's still calculating
+X actually, this is probably because it happens after the frame
+X so really, flush is required whenever the depth sort is called
+X need to check this--isn't this referring to DISABLE_DEPTH_TEST?
+X ENABLE_DEPTH_SORT causing trouble with MovieMaker
+X need to make the flush() api accessible
+X http://dev.processing.org/bugs/show_bug.cgi?id=692
+X image smoothing
+X straighten out default vs. ACCURATE vs. whatever
+X Java2D and P3D and OpenGL are all inconsistent
+o need to be able to do hint() to do nearest neighbor filtering
+X http://dev.processing.org/bugs/show_bug.cgi?id=685
+o imageDetail(), textDetail(), etc?
+o decisions on image smoothing vs. text smoothing vs. all
+
+
+0148 core
+X tweaks to PGraphicsOpenGL to support GLGraphics
+
+
+0147 core
+X processing sketches not restarting after switching pages in safari
+X http://dev.processing.org/bugs/show_bug.cgi?id=581
+
+cleaning
+X misshapen fonts on osx (apple fixed their bug)
+X http://dev.processing.org/bugs/show_bug.cgi?id=404
+
+
+0146 core
+X fix the internal file chooser so that people don't need to make their own
+X threading is a problem with inputFile() and inputFolder()
+X dynamically load swingworker?
+o remove saveFile() methods?
+o write up examples for these instead?
+o start an integration section?
+X get() in java2d not honoring imageMode or rectMode
+X add imageMode(CENTER) implementation
+X add a bunch of changes to the reference to support this
+X Duplicate 3d faces in beginRaw() export
+X this was actually doubling geometry, potentially a bit of a disaster
+X http://dev.processing.org/bugs/show_bug.cgi?id=737
+o bezierVertex YZ Plane fill problem
+X http://dev.processing.org/bugs/show_bug.cgi?id=752
+X weird coplanar stuff, shouldn't be doing 3D anyway
+
+cleanup
+X switch to requestImage() (done in 0145)
+o can bug 77 be fixed with a finalizer? (no, it cannot)
+X make sure that images with alpha still have alpha in current code
+X text in rectangle is drawing outside the box
+X http://dev.processing.org/bugs/show_bug.cgi?id=844
+X points missing in part of screen
+X http://dev.processing.org/bugs/show_bug.cgi?id=269
+
+
+0145 core
+X separate x/y axis on sphereDetail() params
+X http://dev.processing.org/bugs/show_bug.cgi?id=856
+X make sure docs for PImage use createImage
+X add notes about JOGLAppletLauncher
+X http://download.java.net/media/jogl/builds/nightly/javadoc_public/com/sun/opengl/util/JOGLAppletLauncher.html
+X added to javadoc
+o need a halt() method which will kill but not quit app (sets finished?)
+o exit() will actually leave the application
+o this may in fact only be internal
+X this is just the stop() method, though maybe we need to document it
+X text(String, float, float, float, float) draws text outside box
+X http://dev.processing.org/bugs/show_bug.cgi?id=844
+X implement textAlign() for y coords in text rect
+X need to add reference for this
+X textAlign() bottom now takes textDescent() into account
+X remove gzip-related hint()
+
+threading
+X major threading overhaul before 1.0 (compendium)
+X http://dev.processing.org/bugs/show_bug.cgi?id=511
+X ewjordan has added a good trace of the badness
+X need to move off anim off the main event thread
+X move away from using method like display
+X look into opengl stuff for dealing with this
+X move addListeners() calls back out of PGraphics
+X resize window will nuke font setting
+X textFont() used in setup() is null once draw() arrives
+X http://dev.processing.org/bugs/show_bug.cgi?id=726
+X colorMode() set inside setup() sometimes not set once draw() arrives
+X http://dev.processing.org/bugs/show_bug.cgi?id=767
+X applet sizing issues with external vm
+X could this possibly be related to the linux bug?
+X http://dev.processing.org/bugs/show_bug.cgi?id=430
+X alloc() stuff not fixed because of thread halting
+X problem where alloc happens inside setup(), so, uh..
+X http://dev.processing.org/bugs/show_bug.cgi?id=369
+X should instead create new buffer, and swap it in next time through
+X sonia (and anything awt) is locking up on load in rev 91
+X prolly something w/ the threading issues
+X paint is synchronized in 0091
+X however this is a necessity, otherwise nasty flickering ensues
+X and using a "glock" object seems to completely deadlock
+X http://dev.processing.org/bugs/show_bug.cgi?id=46
+o claim that things are much slower in 107 vs 92
+o http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Suggestions;action=display;num=1141763531
+X hopefully this is cleaned up by removing some of the synchronization
+X sketches lock up when system time is changed
+X http://dev.processing.org/bugs/show_bug.cgi?id=639
+X can draw() not be run on awt event thread?
+X look into opengl stuff for dealing with this
+o "is there a better way to do this" thread in lists folder
+X framerate that's reported is out of joint with actual
+X http://dev.processing.org/bugs/show_bug.cgi?id=512
+X accuracy of frame timer is incorrect
+X seems to be aliasing effect of low resolution on millis()
+X so rates coming out double or half of their actual
+X probably need to integrate over a rolling array of 10 frames or so
+X frameRate() speeds up temporarily if CPU load drops dramatically
+X http://dev.processing.org/bugs/show_bug.cgi?id=297
+o perhaps add a hint(DISABLE_FRAMERATE_DAMPER)
+X fix the flicker in java2d mode
+X http://dev.processing.org/bugs/show_bug.cgi?id=122
+X framerate(30) is still flickery and jumpy..
+X not clear what's happening here
+X appears to be much worse (unfinished drawing) on macosx
+X try turning off hw accel on the mac to see if that's the problem
+
+
+0144 core
+X if loading an image in p5 and the image is bad, no error msg shown
+X that is, if a loadImage() turns up an access denied page
+X added an error message for this, and the image width and height will be -1
+X added loadImageAsync() for threaded image loading
+
+opengl fixes
+X incorporate changes from andres colubri into PGraphicsOpenGL
+X most of the changes incorporated, something weird with constructors
+X use gluErrorString() for glError() stuff
+X PGraphicsOpenGL.java:
+X directionalLight() and .pointLight() are both calling
+X glLightNoAmbient() which then creates a new FloatBuffer
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1199376364
+
+
+0143 core
+X some fonts broken in java 1.5 on osx have changed again
+X http://dev.processing.org/bugs/show_bug.cgi?id=407
+X filed as bug #4769141 with apple http://bugreport.apple.com/
+X appears that asking for the postscript name no longer works
+o fix "create font" and associated font stuff to straighten it out
+X was grabbing the wrong native font with ico sketch
+X seems that the psname is no longer a good way to grab the font? related?
+X available font issues
+X is getFontList returning a different set of fonts from device2d?
+X try it out on java 1.3 versus 1.4
+X getAllFonts() not quite working for many fonts
+X i.e. Orator Std on windows.. macosx seems to be ok
+X is getFamilyNames() any different/better?
+X when did this break? 1.4.1? 1.4.x vs 1.3?
+X may be that cff fonts won't work?
+X or is it only those with ps names?
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1117445969
+o leading looks too big, at least in PGraphics2 with news gothic
+X though prolly the converted version of the .ttf?
+X add a fix so that negative angle values won't hork up arc() command
+X add resize() method to PImage
+
+
+0142 core
+X update iText in PDF library to 2.1.2u
+X loadStrings(".") should not list directory contents
+X http://dev.processing.org/bugs/show_bug.cgi?id=716
+
+
+0141 core
+X no changes to core in 0141
+
+
+0140 core
+X add static version of loadBytes() that reads from a File object
+X slightly clearer error messages when OpenGL stuff is missing
+
+
+0139 core
+X no changes to core in 0139
+
+
+0138 core
+X improve tessellation accuracy by using doubles internally
+X http://dev.processing.org/bugs/show_bug.cgi?id=774
+
+
+0137 core
+X add gz handling for createOutput()
+X change openStream() to createInput() (done in 0136)
+X add createOutput()
+X deprecate openStream() naming
+
+
+0136 core
+X add static version of saveStream() (uses a File and InputStream object)
+X A "noLoop()" sketch may be unresponsive to exit request
+X http://dev.processing.org/bugs/show_bug.cgi?id=694
+X Fixed bug with subset() when no length parameter was specified
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Syntax;action=display;num=1196366408
+X http://dev.processing.org/bugs/show_bug.cgi?id=707
+X figure out why tiff images won't open with after effects
+X http://dev.processing.org/bugs/show_bug.cgi?id=153
+X open with photoshop, resave, see which tags change
+X specifically, which tags that were in the original image file
+X perhaps something gets corrected?
+X had a fix, but decided not to re-implement the loadTIFF stuff too
+X fix for bezierTangent() problem from dave bollinger
+X http://dev.processing.org/bugs/show_bug.cgi?id=710
+X implement curveTangent (thanks to davbol)
+X http://dev.processing.org/bugs/show_bug.cgi?id=715
+X fix problem with get() when imageMode(CORNERS) was in use
+X fix bug with splice() and arrays
+X http://dev.processing.org/bugs/show_bug.cgi?id=734
+X 'screen' is now static
+X undo this--may need to be better about specifying screen and all
+X PImage mask doesn't work after first call
+X http://dev.processing.org/bugs/show_bug.cgi?id=744
+X load and save tga results in upside down tga
+X http://dev.processing.org/bugs/show_bug.cgi?id=742
+X fix problem with g.smooth always returning false in JAVA2D
+X http://dev.processing.org/bugs/show_bug.cgi?id=762
+X add XMLElement (not filename) constructor to SVG lib
+X http://dev.processing.org/bugs/show_bug.cgi?id=773
+
+
+0135 core
+X modelX/Y/Z still having trouble
+X http://dev.processing.org/bugs/show_bug.cgi?id=486
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Suggestions;action=display;num=1186614415
+X add docs for model/screen/Y/Z
+X added for model, along with example.
+X screen was already complete
+X bring back opengl mipmaps (create them myself? try w/ newer jogl?)
+X opengl mipmaps are leaking (regression in spite of #150 fix)
+X http://dev.processing.org/bugs/show_bug.cgi?id=610
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=OpenGL;action=display;num=1193967684
+X seems to not actually be a problem on mbp, try desktop?
+X copy() was needing updatePixels() when used with OPENGL or JAVA2D
+X http://dev.processing.org/bugs/show_bug.cgi?id=681
+X check on the bug report for this one as well
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Syntax;action=display;num=1173394373
+
+earlier
+o add notes about fixing serial on the mac to the faq (and link to bug)
+X not necessary, hopefuly things working better now
+X utf8 and encodings
+X createWriter() and createReader() that take encodings
+X xml files seem to be a lot of UTF-8
+X xml stuff
+X getItem("name");
+X getItems("name"); (same, but looks for multiple matches
+X getItem("path/to/item");
+o or could use getItem and getItemList? getItemArray()?
+o read more about xpath
+X parse xml from a string object
+X not have to just use Reader
+X add mention of this to the board
+o update to new version of jogl
+X fix mini p5 bugs for eugene
+
+
+0134 core
+X add noLights() method
+X http://dev.processing.org/bugs/show_bug.cgi?id=666
+X redraw the screen after resize events (even with noLoop)
+X http://dev.processing.org/bugs/show_bug.cgi?id=664
+o problem with transparency in mask()
+o http://dev.processing.org/bugs/show_bug.cgi?id=674
+X mark bug as invalid, using fill() instead of tint()
+X move to UTF-8 as native format for core file i/o operations
+X update reference to document the change
+o jogl glibc 2.4 problem on linux
+o move back to previous jogl until 1.1.1 is released
+X http://dev.processing.org/bugs/show_bug.cgi?id=675
+o deal with opengl applet export changes
+o what is deployment suggestion for all the different platforms?
+o can the jar files actually provide the DLLs properly?
+X revert back to jogl 1.0
+
+
+0133 core
+X fix problem with "export to application" and opengl
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=OpenGL;action=display;num=1193142573
+X add focus requests so that better chance of keys etc working
+X http://dev.processing.org/bugs/show_bug.cgi?id=645
+X argh, these make things worse (P3D run internal)
+X add stuff about classversionerrors to the reference
+X also update the libraries page
+X fix background() with P3D and beginRaw()
+X endRaw() has a problem with hint(ENABLE_DEPTH_SORT)
+X because the triangles won't be rendered by the time endRaw() is called
+X force depth sorted triangles to flush
+X is mousePressed broken with noLoop() or redraw()?
+X sort of but not really, add notes to reference about it
+
+cleaning
+o calling graphics.smooth(), graphics.colorMode() outside begin/endDraw
+o this causes everything to be reset once the draw occurs
+o kinda seems problematic and prone to errors?
+X nope, just need to say to do all commands inside begin/endDraw
+o finish implementation so 1.1 support can return
+X http://dev.processing.org/bugs/show_bug.cgi?id=125
+o check into ricard's problems with beginRecord()
+X i believe these were caused by linux java2d issues
+X beginFrame()/beginDraw() and defaults()
+X when should these be called, when not?
+X seems as though the begin/end should happen inside beginRaw/Record
+X defaults() gets called by the size() command in PApplet
+o would be cool if could sort w/o the sort class..
+o meaning use reflection to sort objects, just by implementing a few methods
+o would be much simpler and less confusing than new Sort() etc
+o or would it be ridiculously slow?
+X just using Comparator instead, since moving to Java 1.4
+X make a PException that extends RuntimeException but packages an ex?
+X http://java.sun.com/docs/books/tutorial/essential/exceptions/runtime.html
+X no, not necessary, and exceptions suck
+o need to write an error if people try to use opengl with 1.3 (i.e. on export)
+o don't let users with java < 1.4 load OPENGL
+o http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Contribution_3DOpenGL;action=display;num=1114368123;start=3
+o catch security exceptions around applet i/o calls
+o not just for saving files, but provide better error msgs when
+o attempting to download from another server
+X nope, just cover this in the reference
+o files not in the data folder (works in env, not in sketch)
+X mentioned repeatedly in the docs
+o fix link() to handle relative URLs
+o http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1081710684
+X more trouble (and bug-worthy) than it's worth
+o put SecurityException things around file i/o for applets
+o rather than checking online(), since applets might be signed
+X no, better to let errors come through
+o slow on java2d, fast on p3d
+o http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1115276250;start=3
+
+ancient
+o strokeWeight is still broken
+o setting stroke width on circle makes odd patterns
+o http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1077013848
+o http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1080347160
+o more weirdness with stroke on rect, prolly not alpha
+o http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1085799526
+o rect is not getting it's stroke color set
+o http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1073582391;start=0
+o weird problem with drawing/filling squares
+o http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1077226984
+o alpha of zero still draws boogers on screen
+o http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1073329613;start=0
+o http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1080342288;start=0
+o break apart functions into local (placement) and override (blitting)
+o just have a "thin_flat_line" option in opengl code
+o is quad strip broken or not behaving as expected?
+X may be correct, it worked for nik
+X inside draw() mode, delay() does nothing
+X delay might be a good way to signal drawing to the screen/updating
+X set(x, y, image) x, y not setting with processing
+
+fixed earlier
+X is the texture[] array in PGraphics3D causing the problems with memory?
+X actually it's a PGraphicsGL problem..
+X maybe the image binding not getting unbound?
+o should image i/o be moved into PImage?
+o still needs applet object, so it's not like this is very useful
+o external PImage methods could take stream, i suppose..
+X relevant parts were moved in, others not
+o loadImage() using spaces in the name
+o if loadImage() with spaces when online(), throw an error
+o get tiff exporter for p5 to support argb and gray
+X would also need to modify the tiff loading code,
+X because the header would be different
+X http://dev.processing.org/bugs/show_bug.cgi?id=343
+X map() is not colored, neither is norm
+X image outofmemoryerror for casey's students
+X http://dev.processing.org/bugs/show_bug.cgi?id=355
+X this may be related to a ton of other memory bugs
+X 1.5.0_07 and 1.4.2_12 contain the -XX:+HeapDumpOnOutOfMemoryError switch
+X invaluable for tracking down memory leaks
+X can't replicate anymore
+X texture mapping
+X very odd, "doom era" stuff
+X would it be possible to have a 'slow but accurate' mode?
+X http://dev.processing.org/bugs/show_bug.cgi?id=103
+X fixed in release 0125
+X add hint() and unhint()
+X also add unhint() to the keywords file
+X and maybe remove hint() from keywords_base?
+o present mode is flakey.. applet doesn't always come up
+o seems like hitting stop helps shut it down?
+o is full screen window not being taken down properly?
+o has this fixed itself, or is it an issue with launching externally?
+X seems to be fixed in later java versions
+X rewrite getImpl/setImpl inside opengl
+X placement of 100x100 items is odd
+X happens with P3D and maybe also P2D?
+X http://dev.processing.org/bugs/show_bug.cgi?id=128
+
+
+0132 core
+X an image marked RGB but with 0s for the alpha won't draw in JAVA2D
+X images with 0x00 in their high bits being drawn transparent
+X also if transparency set but RGB is setting, still honors transparency
+X http://dev.processing.org/bugs/show_bug.cgi?id=351
+X improve memory requirements for drawing images with JAVA2D
+X now using significantly less memory
+
+tint/textures
+X tint() and noTint() switching problem in P2D
+X this should be a quick fix
+X http://dev.processing.org/bugs/show_bug.cgi?id=222
+X related to the fill bugs: when fill is identical, no fill applied
+X actually tint() should take over for fill as per-vertex color
+X when textured images are being used
+X http://dev.processing.org/bugs/show_bug.cgi?id=169
+X tint() should set texture color, fill() is ignored with textures
+X add to the reference
+X fix tint() for PGraphics3 (what could be wrong?)
+X tint() honoring alpha but not colored tint
+X maybe not setting fill color when drawing textures
+X guessing it's an implementation issue in sami's renderer
+X check with the a_Displaying example and tint(255, 0, 0, 100);
+X http://dev.processing.org/bugs/show_bug.cgi?id=90
+
+
+0131 core
+X hint(DISABLE_DEPTH_TEST) not behaving consistently
+X http://dev.processing.org/bugs/show_bug.cgi?id=483
+o make hints static - cannot do that
+X clean up hinting mechanism a bit
+X look into jogl anti-aliasing on osx
+o smoothMode(2) and smoothMode(4), right after size()?
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=OpenGL;action=display;num=1175552759
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=OpenGL;action=display;num=1164236069
+X look into capabilities stuff from mike creighton
+X also sets the aa mode on the pc so it no longer needs control panel bunk
+X update to JOGL 1.1.0
+X add gluegen-rt back to the applet export
+X http://download.java.net/media/jogl/builds/nightly/javadoc_public/com/sun/opengl/util/JOGLAppletLauncher.html
+X add print() and println() for long and double
+X http://dev.processing.org/bugs/show_bug.cgi?id=652
+X fix minor bug in saveStream() (undocumented)
+X "this file is named" errors don't like subdirectories
+X need to strip off past the file separator or something
+
+
+0130 core
+X fixed problem with size() and the default renderer
+X the renderer was being reset after setup(),
+X so anything that occurred inside setup() was completely ignored.
+X http://dev.processing.org/bugs/show_bug.cgi?id=646
+X http://dev.processing.org/bugs/show_bug.cgi?id=648
+X http://dev.processing.org/bugs/show_bug.cgi?id=649
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1192873557
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1192731014
+
+
+0129 core
+X width and height not always set properly
+X http://dev.processing.org/bugs/show_bug.cgi?id=642
+X bring back background() with alpha
+
+
+0128 core
+X remove PFont reflection stuff
+X remove cursor reflection stuff
+X fix up sorting functions
+X implement sortCompare() and sortSwap()
+X discuss this with casey
+X also could be using Arrays.sort(blah) with Comparable (1.2+)
+X make sorting functions static
+X use methods from Arrays class, cuts down on code significantly
+X implement sortCompare() and sortSwap()
+X discuss this with casey
+o also could be using Arrays.sort(blah) with Comparable (1.2+)
+X make sorting functions static?
+o should loadFont() work with ttf files (instead of createFont?)
+X otherwise loadFont() would work with font names as well, awkward
+X better to use createFont() for both
+o jogl issues with some cards on linux, might be fixed with newer jogl
+X http://dev.processing.org/bugs/show_bug.cgi?id=367
+X remove methods for background() to include an alpha value
+X this is undefined territory because of zbuffer and all
+X if you want that effect, use a rect()
+X saveFrame() produces a black background because bg not set correctly:
+X http://dev.processing.org/bugs/show_bug.cgi?id=421
+X background not being set properly
+X http://dev.processing.org/bugs/show_bug.cgi?id=454
+X having shut off the defaults reset, background not getting called for java2d
+X so this will make that other stuff regress again
+X in particular, when the applet is resized, but renderer not changed
+X why aren't background() / defaults() being called for opengl?
+o http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Contribution_3DOpenGL;action=display;num=1118784331
+o simon reports borders on P3D and OPENGL if background() not called
+X window fixed at 100x100 pixels
+X http://dev.processing.org/bugs/show_bug.cgi?id=197
+X width/height on problem machine prints out as:
+X 100x100 issues are exhibited on bh140c PCs, test and fix!
+X 100,200 and 128,200
+o AIOOBE on PLine 757.. halts renderer
+o fix erik's problems with export (also in bugs db)
+X draw() called twice in vista with java 1.6
+X http://dev.processing.org/bugs/show_bug.cgi?id=587
+
+cleanup from previous releases
+X P3D not doing bilinear interpolation in text and images
+X because smooth() has to be set (and smooth throws an error in P3D)
+X how should this be handled? a hint? allowing smooth()?
+X probably just allow smooth() but don't smooth anything
+o pdf export ignoring transparency on linux
+o check to see if this is the case on other linux machines
+o seems to be working fine on windows
+o http://dev.processing.org/bugs/show_bug.cgi?id=345
+X change how java version is determined on mac
+X http://developer.apple.com/technotes/tn2002/tn2110.html
+X (this tn provides no guidance for macos8/9.. gah)
+o little window showing up on macosx when running
+X never able to confirm, probably just old java bug
+X http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1081284410
+o flicker happening on osx java 1.4, but not 1.3:
+o http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1083184297
+o don't let users on < 1.3 load JAVA2D
+X set upper bound on framerate so as not to completely hose things?
+
+fixed in 0127
+X ARGB problems with createGraphics
+o P3D from createGraphics needs to be marked RGB not ARGB
+X http://dev.processing.org/bugs/show_bug.cgi?id=160
+X http://dev.processing.org/bugs/show_bug.cgi?id=428
+X http://dev.processing.org/bugs/show_bug.cgi?id=482
+X http://dev.processing.org/bugs/show_bug.cgi?id=530
+X http://dev.processing.org/bugs/show_bug.cgi?id=527
+
+reasons to drop 1.1 support (and support 1.3+)
+X remove reflection from createFont() constructor/methods in PFont
+X this would make PFont much smaller
+X array functions could be done through Arrays.xxx class
+X although some of these may be built in
+X sorting could be done through built-in sort() class
+X split() function could echo the built in split/regexp setup
+X and add features for regexp
+X could introduce use of Timer class in examples
+X also use SwingWorker to launch things on other threads
+X weirdness of two modes of handling font metrics
+X textFontNativeMetrics gives deprecation error
+X getFontList stuff in PFont causes problems
+
+
+0127 core
+X pixel operations are broken in opengl
+X get(), set(), copy(), blend(), loadPixels, updatePixels()
+X set(x, y, image) y reversed in openGL
+X background(image) also broken
+X also textMode(SCREEN)
+X http://dev.processing.org/bugs/show_bug.cgi?id=91
+o replaceAll() not supported by 1.1
+o http://dev.processing.org/bugs/show_bug.cgi?id=561
+o make version of loadBytes that checks length of the stream first
+o this might not be worth it
+o the number of cases where this works is small (half of url streams)
+o and who knows if the value returned will be correct
+o (i.e. will it be the uncompressed or compressed size of the data?)
+
+createGraphics() issues
+X offscreen buffers fail with texture mapping
+X pixels not being set opaque (only with textures?)
+X http://dev.processing.org/bugs/show_bug.cgi?id=594
+X add note to createGraphics() docs that opacity at edges is binary
+X PGraphics problem with fillColor
+X http://dev.processing.org/bugs/show_bug.cgi?id=468
+
+fixed earlier
+X add to open() reference problems with mac
+X need to use the 'open' command on osx
+X or need to do this by hand
+X prolly better to do it by default, since on windows we use cmd?
+X check to see if the user has 'open' in there already
+X they can call Runtime.getRuntime().exec() if they want more control
+
+fixed earlier (in 0125) by ewjordan
+X accuracy in P3D is very low
+X http://dev.processing.org/bugs/show_bug.cgi?id=95
+X textured polys throwing a lot of exceptions (ouch)
+X http://dev.processing.org/bugs/show_bug.cgi?id=546
+X polygons in z axis with nonzero x or y not filling properly
+X http://dev.processing.org/bugs/show_bug.cgi?id=547
+
+
+0126 core
+o rect() after strokeWeight(1) gives wrong coords
+X http://dev.processing.org/bugs/show_bug.cgi?id=535
+X bug in osx java 1.4 vs 1.5
+X fix bug in str() methods that take arrays
+X method was not working properly, was using the object reference
+X new version of saveStream()
+X implement auto-gzip and gunzip
+X fix bug where sort() on 0 length array would return null
+X instead, returns an array
+X unregisterXxxx() calls to remove methods from libs
+X http://dev.processing.org/bugs/show_bug.cgi?id=312
+X implemented by ewjordan
+X sort() on strings ignores case
+X mention the change in the reference
+X added MIN_FLOAT, MAX_FLOAT, MIN_INT, MAX_INT to PConstants
+X throw AIOOBE when min() or max() called on zero length array
+o fix lerpColor() to take the shortest route around the HSB scale
+o loadBytes() doesn't do auto gunzip? but loadStrings and createReader do?
+X this might be a good solution for dealing with the differences
+o with loadBytes(), they can use gzipInput (or loadBytesGZ?)
+o although what does openStream do? (doesn't do auto?)
+X auto-gunzip on createReader()
+o add auto-gunzip to loadStrings()
+X others for auto-gunzip?
+X do the same for createWriter() et al
+X disable mipmaps in 0126
+X http://dev.processing.org/bugs/show_bug.cgi?id=610
+X add match() method that returns an array of matched items
+
+
+0125 core
+X more blend() modes (the five listed on the thread below?)
+X http://dev.processing.org/bugs/show_bug.cgi?id=132
+X figure out what the modes should actually be:
+X photoshop: normal, dissolve; darken, multiply, color burn,
+X linear burn; lighten, screen, color dodge, linear
+X dodge; overlay, soft light, hard light, vivid light,
+X linear light, pin light, hard mix; difference,
+X exclusion; hue, saturation, color, luminosity
+X illustrator: normal; darken, multiply, color burn; lighten,
+X screen, color dodge; overlay, soft light, hard light;
+X difference, exclusion; hue, sat, color, luminosity
+X director: Copy, Transparent, Reverse, Ghost, Not copy,
+X Not transparent, Not reverse, Not ghost, Matte, Mask;
+X (below seems more useful:
+X Blend, Add pin, Add, Subtract pin, Background transparent,
+X Lightest, Subtract, Darkest, Lighten, Darken
+X flash:
+X DIFFERENCE: C = abs(A-B);
+X MULTIPLY: C = (A * B ) / 255
+X SCREEN: C= 255 - ( (255-A) * (255-B) / 255 )
+X OVERLAY: C = B < 128 ? (2*A*B/255) : 255-2*(255-A)*(255-B)/255
+X HARD_LIGHT: C = A < 128 ? (2*A*B/255) : 255-2*(255-A)*(255-B)/255
+X SOFT_LIGHT: C = B < 128 ? 2*((A>>1)+64)*B/255 : 255-(2*(255-((A>>1)+64))*(255-B)/255)
+X jre 1.5.0_10 is still default at java.com.. blech
+X http://dev.processing.org/bugs/show_bug.cgi?id=513
+X constant CENTER_RADIUS will be changed to just RADIUS
+X CENTER_RADIUS is being deprecated, not removed
+X remove CENTER_RADIUS from any p5 code (i.e. examples)
+X split() inconsistency (emailed casey, will discuss later)
+X make split(String, String) behave like String.split(String)
+X and make current split(String) into splitTokens(String)
+X that means split(String) no longer exists
+o add splitTokens() documentation
+o document new version of split() and regexp
+o should we mention String.split?
+X ironed out more of the preproc parseXxxx() functions
+X deal with targa upside-down and non-rle encoding for tga images
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1171576234
+X change println(array) to be useful
+o document using join() for old method
+X remove print(array) since it's silly?
+X make sure it's not in the reference
+X [0] "potato", [1] "tomato", [2] "apple"
+X fix filter(GRAY) on an ALPHA image to produce a good RGB image
+
+0125p2
+X updatePixels ref is wrong
+X has x/y/w/h version
+X the reference is also cut off
+X make ENTER, TAB, etc all into char values (instead of int)
+X some way to vertically center text
+X either by setting its middle vertical point
+X or by setting a top/bottom for the rectangle in which it should be placed
+o maybe textAlign(CENTER | VERTICAL_CENTER);
+X or TOP, MIDDLE, and BOTTOM
+o textAlign(CENTER | TOP);
+o could even have textAlign(CENTER) and textAlign(TOP) not replace each other
+X or textAlign(LEFT, MIDDLE); -> this one seems best
+X add reference for new param, and update keywords.txt
+X given to andy
+
+0125p3
+X PImage.save() method is not working with get()
+X http://dev.processing.org/bugs/show_bug.cgi?id=558
+X NullPointerException in Create Font with "All Characters" enabled
+X http://dev.processing.org/bugs/show_bug.cgi?id=564
+X added min() and max() for float and int arrays
+X need to update reference
+X moved around min/max functions
+X opengl image memory leaking
+X when creating a new PImage on every frame, slurps a ton of memory
+X workaround is to write the code properly, but suggests something bad
+X http://dev.processing.org/bugs/show_bug.cgi?id=150
+X opengl keeping memory around..
+X could this be in vertices that have an image associated
+X or the image buffer used for textures
+X that never gets cleared fully?
+X registerSize() was registering as pre() instead
+X http://dev.processing.org/bugs/show_bug.cgi?id=582
+X set() doesn't bounds check
+X this shouldn't actually be the case
+X http://dev.processing.org/bugs/show_bug.cgi?id=522
+X get()/set() in PGraphicsJava2D don't bounds check
+X was actually a dumb error in setDataElements()
+X set modified to true on endDraw() so that image updates properly
+X http://dev.processing.org/bugs/show_bug.cgi?id=526
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Syntax;action=display;num=1171574044
+
+0125p4 (in progress)
+X significant improvement to text and images in opengl
+X now using mipmaps to interpolate large and small images
+X fix bug with mipmapping on radeon 9700
+X things not showing up in linux
+X this may be fixed along with bug #341
+X probably threading issue, 98 doesn't have any trouble
+X signs point to Runner or PApplet changes between 98 and 99
+X commenting out applet.setupFrameResizeListener()
+X in line 307 from Runner.java solved the problem
+X http://dev.processing.org/bugs/show_bug.cgi?id=282
+X size of sketch different in setup() and draw() on linux
+X make sure that the sketch isn't being sized based on bad insets
+X problem with resizing the component when the frame wasn't resizable
+X http://dev.processing.org/bugs/show_bug.cgi?id=341
+X major rework of the open() command
+X add gnome-open/kde-open for with PApplet.open()
+X add open (-a?) on osx to the open() command
+X make changes in the javadoc and reference
+X opengl crashes when depth sorting more than two textured shapes
+X http://dev.processing.org/bugs/show_bug.cgi?id=560
+
+ewjordan stuff (changes checked in)
+X rect() changes size as it changes position
+X http://dev.processing.org/bugs/show_bug.cgi?id=95
+X strange texture warping in P3D
+X hint(ENABLE_ACCURATE_TEXTURES)
+X http://dev.processing.org/bugs/show_bug.cgi?id=103
+X lines skip on 200x200 surface because of fixed point rounding error
+X http://dev.processing.org/bugs/show_bug.cgi?id=267
+X this may be same as 95
+X Polygons parallel to z-axis not always filling with nonzero x or y
+X http://dev.processing.org/bugs/show_bug.cgi?id=547
+
+
+0124 core
+X with smooth() turned off, shouldn't be smoothing image on resize
+X but on osx, apple defaults the image smoothing to true
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Programs;action=display;num=1164753510
+X http://developer.apple.com/documentation/Java/Conceptual/JavaPropVMInfoRef/Articles/JavaSystemProperties.html#//apple_ref/doc/uid/TP40001975-DontLinkElementID_6
+X background(0, 0, 0, 0) was resetting stroke, smooth, etc.
+X make imageImpl() use WritableRaster in an attempt to speed things up
+X fix weird situation where fonts used in more than one renderer wouldn't show
+X opengl doesn't draw a background for the raw recorder
+X change P3D to smooth images nicely (bilinear was disabled)
+X ambientLight(r,g,b) was still ambientLight(r,g,r)
+X http://dev.processing.org/bugs/show_bug.cgi?id=465
+X fix from dave bollinger for the POSTERIZE filter
+X http://dev.processing.org/bugs/show_bug.cgi?id=399
+X fix PImage regression in 0124 and the cache crap
+X added a version of trim() that handles an entire array
+X removed contract(), one can use expand() and subset() instead
+X backgroundColor to cccccc instead of c0c0c0
+X loadImage() requires an extension, maybe add a second version?
+X loadImage("blah", "jpg");
+X otherwise people have to use strange hacks to get around it
+X also chop off ? from url detritus
+X also just pass off to default createImage() if no extension available
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Syntax;action=display;num=1165174666
+X http://dev.processing.org/bugs/show_bug.cgi?id=500
+X java 1.5.0_10 breaks jogl
+X add error message to p5 about it
+X http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6504460
+X http://www.javagaming.org/forums/index.php?topic=15439.0
+X upgrade to 1.5.0_11 or later:
+X http://java.sun.com/javase/downloads/index_jdk5.jsp
+X or downgrade to 1.5.0_09
+X http://java.sun.com/products/archive/j2se/5.0_09/index.html
+X no disk in drive error
+X was this something that changed with the java updates? (1.5_10)
+X doesn't seem to be, still not sure
+X problem was the floppy drive.. gak
+X http://dev.processing.org/bugs/show_bug.cgi?id=478
+X copy() sort of broken in JAVA2D
+X example sketch posted with bug report
+X http://dev.processing.org/bugs/show_bug.cgi?id=372
+o saveStrings(filename, strings, count)
+o otherwise the save is kinda wonky
+o or maybe that should just be done with the array fxns
+
+fixed earlier
+o sketches often freeze when stop is hit on an HT machine
+o need to test the examples cited on pardis' machine
+o http://dev.processing.org/bugs/show_bug.cgi?id=232
+X debug NumberFormat InterruptedException on dual proc machine
+X use notify() instead of interrupt()?
+X or Thread.currentThread() should be checked first?
+o svg loader is on the list for 1.0
+o maybe include as part of PApplet (casey thinks so)
+X using gl, lines don't show up in pdf with record (they're ok with p3d)
+X http://dev.processing.org/bugs/show_bug.cgi?id=325
+o with network connection
+o download a copy of the source for 0069, get the renderer
+o svn mv PGraphics2 PGraphicsJava
+o version of BApplet that replaces g. with ai. or pdf.
+
+
+0123 core
+X setup() and basic mode apps not working
+X http://dev.processing.org/bugs/show_bug.cgi?id=463
+
+
+0122 core
+X noiseSeed() only works once, before the arrays are created
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1162856262
+X make lerpColor honor the current color mode
+X lerpColor(c1, c2, amt, RGB/HSB/???)
+o test this out for a bit
+o though that's awkward b/c colors always RGB
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Suggestions;action=display;num=1160096087
+X regression in P3D that prevents point() from drawing
+X problem is with setup_vertex() not adding similar points
+X http://dev.processing.org/bugs/show_bug.cgi?id=444
+X if doing openstream on url, says that "the file" is missing or invalid
+X add notes about it being a url
+
+fixed earlier, bug cleaning
+X gray background in pdf (using both gl and p3d)
+X http://dev.processing.org/bugs/show_bug.cgi?id=324
+X verified as fixed in 0122
+
+
+0121 core
+X need to document changes to int() (no longer accepts boolean)
+X background(0, 0, 0, 0) is the way to really clear everything with zeroes
+X or background(0, 0), but the former is prolly better conceptually
+X how to clear the screen with alpha? background(0, 0, 0, 0)?
+o background(EMPTY) -> background(0x01000000) or something?
+X size(), beginRecords(), beginRaw(), createGraphics()
+X broken for file-based renderers in 0120
+X http://dev.processing.org/bugs/show_bug.cgi?id=434
+
+
+0120 core
+X fixed error when using hint(ENABLE_NATIVE_FONTS) with JAVA2D
+X java.lang.IllegalArgumentException:
+X null incompatible with Global antialiasing enable key
+X fix issue where ambientLight(r, g, b) was instead ambientLight(r, g, r)
+X http://dev.processing.org/bugs/show_bug.cgi?id=412
+X createFont() should always use native fonts
+X need to warn that fonts may not be installed
+X recommend that people include the ttf if that's the thing
+X or rather, that this is only recommended for offline use
+X fix 3D tessellation problems with curveVertex and bezierVertex
+X actually was z = Float.MAX_VALUE regression
+X http://dev.processing.org/bugs/show_bug.cgi?id=390
+X two examples in sketchbook
+X this has been reported several times
+X concave polygons having trouble if points come back to meet
+X tesselator/triangulator gets confused when points doubled up
+X might need to avoid previous vertex hitting itself
+X http://dev.processing.org/bugs/show_bug.cgi?id=97
+X graphics gems 5 has more about tessellation
+X polygons perpendicular to axis not drawing
+X is this a clipping error?
+X probably a triangulation error, because triangles work ok
+X http://dev.processing.org/bugs/show_bug.cgi?id=111
+X problem is that the area of the polygon isn't taking into account z
+X lookat is now camera(), but not fixed in the docs
+X add notes to the faq about the camera changes on the changes page
+o update run.bat for new quicktime
+o unfortunately this is messy because qtjava sometimes has quotes
+o and qtsystem might be somewhere besides c:\progra~1
+X run.bat has been removed from current releases
+X registering font directories in pdf.. is it necessary?
+X (commented out for 0100)
+X re-added for 0120
+o when re-calling size() with opengl, need to remove the old canvas
+o need to check to see if this is working properly now
+X passing applet into createGraphics.. problems with re-adding listeners
+X since the listeners are added to the PApplet
+X i think the listeners aren't re-added, but need to double check
+X createGraphics() having problems with JAVA2D, and sometimes with P3D
+X http://dev.processing.org/bugs/show_bug.cgi?id=419
+X with default renderer, no default background color?
+X only sometimes.. why is this?
+X only call defaults() when it's part of a PApplet canvas
+X make sure that defaults() is no longer necessary
+X don't want to hose PGraphics for others
+X both for pdf, and making background transparent images
+X PGraphics3D should alloc to all transparent
+X unless it's the main drawing surface (does it know on alloc?)
+X in which case it should be set to opaque
+X have createGraphics() create a completely transparent image
+X and also not require defaults() to be called
+X make a note in the createFont() reference that 1.5 on OS X has problems
+o if calling beginPixels inside another, need to increment a counter
+o otherwise the end will look like it's time to update
+o which may not actually be the case
+o i.e. calling filter() inside begin/end block
+X get creating new PGraphics/2/3 working again
+X http://dev.processing.org/bugs/show_bug.cgi?id=92
+X maybe createGraphics(200, 200) to create same as source
+X createGraphics(200, 200, P2D) to create 2D from 3D
+X also, drawing a PGraphics2 doesn't seem to work
+X new PGraphics2 objects are set as RGB, but on loadPixels/updatePixels
+X they're drawn as transparent and don't have their high bits set
+X problems between modelX between alpha and beta
+X http://dev.processing.org/bugs/show_bug.cgi?id=386
+X y may be flipped in modelX/Y/Z stuff on opengl
+X is this the same bug? assuming that it is
+
+in previous releases
+X when using PGraphics, must call beginFrame() and endFrame()
+X also need to be able to turn off MemoryImageSource on endFrame
+X call defaults() in beginFrame()
+X should PGraphics be a base class with implementations and variables?
+X then PGraphics2D and PGraphics3D that subclass it?
+X (or even just PGraphics2 and PGraphics3)
+X also rename PGraphics2 to PGraphicsJava
+X it's goofy to have the naming so different
+X tweak to only exit from ESC on keyPressed
+o probably should just make this a hint() instead
+X just documented in reference instead
+o metaballs example dies when using box()
+o long string of exceptions, which are also missing their newlines
+X grabbing sun.cpu.endian throws a security exception with gl applets
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Contribution_3DOpenGL;action=display;num=1114368123
+
+
+0119 core
+X add saveStream() method
+X change to handle Java 1.5 f-up where URLs now give FileNotFoundException
+X http://dev.processing.org/bugs/show_bug.cgi?id=403
+X add unlerp() method
+
+
+0118 core
+X replace jogl.jar with a signed version
+X fix the export.txt file for the linux release
+X fix problem with setting the parent and the PDF renderer
+
+
+0117 core
+X no changes, only to the build scripts
+
+
+0116 core
+X make background() ignore transformations in JAVA2D
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1147010374
+o createGraphics to not require defaults()
+X can't do, because an end() function must be called to clear the renderer
+X add "hide stop button" arg for PApplet
+X beginFrame/endFrame -> beginDraw/endDraw
+X add new constant for the DXF renderer
+X array utilities on Object[] are worthless.. fix it with reflection?
+X see if reflection will allow expand for all class types
+X expand, append, contract, subset, splice, concat, reverse
+X typed version of array functions:
+X append(), shorten(), splice, slice, subset, concat, reverse
+X http://dev.processing.org/bugs/show_bug.cgi?id=115
+X fix issue where processing applets would run extremely fast
+X after having been starved of resources where there framerate dropped
+X http://dev.processing.org/bugs/show_bug.cgi?id=336
+X added color/stroke/tint/fill(#FF8800, 30);
+X test imageio with images that have alpha (does it work?)
+X nope, doesn't, didn't finish support
+X http://dev.processing.org/bugs/show_bug.cgi?id=350
+X openStream() fails with java plug-in because non-null stream returned
+X http://dev.processing.org/bugs/show_bug.cgi?id=359
+X update jogl to latest beta 5
+X make framerate into frameRate (to match frameCount)
+X AIOOBE in P3D during defaults/background/clear
+X PGraphics.clear() problem from workbench and malware stuff
+X had to put synchronized onto draw and size()
+X actually it'll work if it's only on size()
+X the sync on the mac hangs an applet running by itself
+X even though it seems to be ok for a component
+X thread sync problem with allocation
+X http://dev.processing.org/bugs/show_bug.cgi?id=369
+X major threading change to use wait()/notifyAll() instead of interrupt/sleep
+X noLoop() at end of setup is prolly b/c of interruptedex
+X need to not call Thread.interrupt()
+X opengl + noLoop() causes InterruptedException
+X check to see noLoop() breakage is fixed in 92 vs 91
+X checked, not fixed
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1115330568
+X http://dev.processing.org/bugs/show_bug.cgi?id=164
+X remove image(filename) and textFont(filename) et al.
+X revision 115 may be saving raw files as TIFF format
+X may be a bug specific to java 1.5 (nope)
+X http://dev.processing.org/bugs/show_bug.cgi?id=378
+X saveFrame() not working for casey
+X problem with tiff loading in photoshop etc
+X check http:// stuff to see if it's a url first on openStream()
+X it's the most harmless, since prolly just a MFUEx
+X fix problem where root of exported sketch won't be checked
+X http://dev.processing.org/bugs/show_bug.cgi?id=389
+X createFont not working from applets (only with .ttf?)
+X throws a security exception because of the reflection stuff
+X http://dev.processing.org/bugs/show_bug.cgi?id=101
+X urls with ampersands don't work with link()
+X Runtime.getRuntime().exec("cmd /c start " + url.replaceAll("&","^&"));
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1149974261
+X fix bug where smooth() was shut off after using text
+X (that had the smoothing turned off when used in "Create Font")
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1148362664
+X fix dxf to use begin/endDraw instead of begin/endFrame
+X fixes axel's bug with dxf export
+X set default frameRate cap at 60
+X otherwise really thrashing the cpu when not necessary
+X jpeg loading may be extremely slow (loadBytes?)
+X seems specific to 0115 versus the others
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1158111639
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1154714548
+X http://dev.processing.org/bugs/show_bug.cgi?id=392
+X loadImage() problems with png and jpg
+X actually it's an issue with some types of jpeg files
+X http://dev.processing.org/bugs/show_bug.cgi?id=279
+X java.lang.IllegalArgumentException:
+X Width (-1) and height (-1) cannot be <= 0
+X identical to what happens when the image data is bad
+X for instance, trying to load a tiff image with the jpg loader
+X http://dev.processing.org/bugs/show_bug.cgi?id=305
+o blend() mode param should be moved to the front
+X nah, works better with the other format
+X make sure there's parity with the copy() functions
+X remove single pixel blend functions
+o blend() should prolly have its mode be the first param
+X move blend() to blendColor() when applying it to a color
+X added lerpColor(), though it needs a new name
+X went back to old image i/o (sometimes caused trouble when exported)
+X http://dev.processing.org/bugs/show_bug.cgi?id=376
+X change reader() to createReader() for consistency?
+X though printwriter is odd for output..
+X also createWriter() and the rest
+o add to docs: save() on a PImage needs savePath() added
+X hint(DISABLE_NATIVE_FONTS) to disable the built-in stuff?
+X or maybe this should be hint(ENABLE_NATIVE_FONTS) instead?
+X figure out default behavior for native text fonts
+X make sure insideDrawWait() is in other resize() methods
+X begin/end/alloc waits to PGraphicsJava2D, PGraphicsOpenGL, PGraphics3D
+X fix bug with fill(#ffcc00, 50);
+X toInt() on a float string needs to work
+X need to check for periods to see if float -> int first
+X shape changes
+X remove LINE_STRIP - tell people to use beginShape() with no params
+X remove LINE_LOOP - tell people to use endShape(CLOSE)
+o also remove POLYGON?
+X may as well remove it
+X though something still needed as an internal constant
+X add endShape(CLOSE) or CLOSED
+X when running as an applet, sketchPath won't be set
+X change the error message slightly
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Syntax;action=display;num=1153150923
+X use parseFloat instead of toFloat()? to be consistent with javascript
+X also clean up some of the casting silliness
+
+more recent
+X only update mouse pos on moved and dragged
+X http://dev.processing.org/bugs/show_bug.cgi?id=170
+X also updates a bug that caused sketches to jump in funny ways
+
+fixed in 0115 / quicktime 7.1
+X color values on camera input flipped on intel macs
+X checked in a change for this recommended on qtjava list
+X http://dev.processing.org/bugs/show_bug.cgi?id=313
+
+really old stuff
+o get loop, noLoop, redraw, and framerate all working in opengl
+o needs custom animator thread..
+o depth() shouldn't be needed for opengl unless actually 3D
+o right now the camera doesn't get set up unless you call depth()
+o box and sphere are broken in gl
+o what should the update image function be called?
+
+
+0115 core
+X remove debug message from loadPixels()
+X remove debug message from PGraphics2.save()
+X fix error message with dxf when used with opengl
+X if file is missing for reader()
+X return null and println an error rather than failing
+X add arraycopy(from, to, count);
+X fix fill/stroke issues in bugs db (bug 339)
+X saveTIFF, saveHeaderTIFF, saveTGA no longer public/static in PImage
+X this was a mistake to expose the api this way
+X more image file i/o in java 1.4
+X add dynamic loading of the jpeg, png, and gif(?) encoder classes
+X http://dev.processing.org/bugs/show_bug.cgi?id=165
+X http://java.sun.com/products/java-media/jai/index.jsp
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Programs;action=display;num=1120174647
+X P5 cannot read files generated by saveFrame()
+X need to update docs re: tga
+X and add support for reading its own uncompressed TIFs
+X http://dev.processing.org/bugs/show_bug.cgi?id=260
+
+
+0114 core
+X added createGraphics(width, height, renderer)
+X no need to use (..., null) anymore
+X fix set() for JAVA2D, also fixes background(PImage) for JAVA2D
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Syntax;action=display;num=1145108567
+X remove "max texture size" debug message
+X flicker with depth sort enabled
+X implement basic depth sorting for triangles in P3D and OPENGL
+X add option to sort triangles back to front so alpha works
+X http://dev.processing.org/bugs/show_bug.cgi?id=176
+o at least add it to the faq, or this would be a test case w/ the sorting
+
+
+0113 core
+X fix for open() on macosx submitted by chandler
+
+
+0112 core
+X saveFrame() issues with JAVA2D on osx
+X http://dev.processing.org/bugs/show_bug.cgi?id=189
+o implement hint(NO_DEPTH_TEST) for opengl
+X already done hint(DISABLE_DEPTH_TEXT);
+X check min/max texture sizes when binding to avoid problems
+X minimum texture size may be 64x64
+X maximum appears to be 2048, on macs maybe 512
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Contribution_3DOpenGL;action=display;num=1137130317
+X fix non-bound textures from mangling everything else
+X http://dev.processing.org/bugs/show_bug.cgi?id=322
+X fix enable/disable textures for some objects
+X also a big problem for fonts
+X calling updatePixels() on each frame fixes the issue (sorta)
+X images are memory leaking pretty badly
+X texture re-allocated on each frame
+X lighting bug introduced in rev 109
+X spotLight has troubles with an invalid value
+X probably somethign weird about the params (3 vs 4) being sent
+X the first spotLight works fine, it's something with the second
+X (the one that follows the mouse)
+X just something to debug in the example
+X regression from contributed code..
+X was using apply() instead of set() in PMatrix inverse copy
+X filter() is also broken (not rewinding the intbuffer)
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Contribution_3DOpenGL;action=display;num=1144561113
+
+sound has been removed
+o duration as an internal param, not a function
+o When a sound is finished playing,
+o it should return to 0 so it can play again
+o Putting sound.loop() in draw() seemed to spawn multiple sounds threads?
+o After a sound is paused, it will only play from where it was paused
+o to its end and will not loop again
+o The ref in PSound2 says volume accepts vals from 0...1
+o but values larger than one increase the volume.
+o SoundEvent // is sound finished?? Can't access now.
+o make java 1.1 version of PSound work properly
+o merge PSound and PSound2 via reflection?
+o once debugged, merge these back together and use reflection
+o (unless it's a messy disaster)
+o Unsupported control type: Master Gain
+o what's actually causing this error?
+o http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1115467831
+o PSound.play() won't play the sound a 2nd time (reopened)
+o http://dev.processing.org/bugs/show_bug.cgi?id=208
+o loadSound apparently broken in java 1.5?
+o http://dev.processing.org/bugs/show_bug.cgi?id=285
+X need to just remove PSound altogether
+
+
+0111 core
+X need to have a better way of getting/figuring out the endian
+X use ByteOrder class in jdk 1.4, since issue is local to JOGL
+X security ex when run as an applet
+X also can no longer assume that macosx is big endian
+X http://dev.processing.org/bugs/show_bug.cgi?id=309
+o making 'run' synchronized caused a freeze on start w/ opengl
+X display() as a function name is problematic
+X causes nothing to show up.. either rename or mark it final
+X http://dev.processing.org/bugs/show_bug.cgi?id=213
+X fix for lights throwing a BufferOverflowException
+
+
+0110 core
+X finish updates for osx and opengl
+X http://developer.apple.com/qa/qa2005/qa1295.html
+X find/build universal version of jogl
+
+
+0109 core
+X loadImage("") produces weird error message
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Programs;action=display;num=1136487954
+X still having strokeCap() problems
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1134011764
+X fixes contributed by willis morse to deal with memory wastefulness
+X should help speed up some types of OPENGL and P3D mode sketches
+
+
+0108 core
+X image(String filename, ...) and textFont(String filename, ...) implemented
+X add notes to faq about video fix
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=VideoCamera;action=display;num=1134871549
+X look into code that fixes crash on camera.settings()
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=VideoCamera;action=display;num=1139376484
+X finish dxf writer that'll work with recordRaw()
+
+
+0107 core
+X no changes, only fixes for "save" bugs
+
+
+0106 core
+X fix bug where more than 512 vertices would cause trouble in P3D and OPENGL
+
+
+0105 core
+X fix some issues with beginRaw and opengl
+
+
+0104 core
+X don't open a window the size of the pdf if in pdf mode
+X need to have some sort of flag in the gfx context that it's visible or not
+o handled inside updateSize()?
+X if it doesn't display to the screen, needs to never show a window
+X basically if the main gfx context isn't viewable, close the window
+X since it may have already been opened at 100x100
+X avoid opening it in the first place?
+X added toolkit getFontMetrics() for shape mode fonts to be able to change size
+X recordRaw() to a PGraphics3 should send 3D data.
+X but recordRaw() to a PGraphics(2) should send only 2D data.
+
+
+0103 core
+X fix stack overflow problem
+X bug in itext implementation on osx (10.4 only?)
+X http://www.mail-archive.com/itext-questions@lists.sourceforge.net/msg20234.html
+
+in previous releases
+X recordFrame() and beginFile()/endFile()
+X how to deal with triangles/lines and triangleCount and lineCount
+X maybe just need a triangleImpl and lineImpl
+X because it's too messy to retain the triangle objects and info
+X calling recordFrame() from mousePressed is important
+X dangerous tho because mouse fxn called just before endFrame
+
+
+0102 core
+X no changes, windows-only release to deal with processing.exe
+
+
+0101 core
+X add dispose() call to the shutdown part of PApplet
+
+
+0100 core
+X user.dir wasn't getting set properly
+X when graphics can be resized, resize rather than creating new context
+X change savePath() et al a great deal, include better docs
+X http://dev.processing.org/bugs/show_bug.cgi?id=199
+X straighten out save() and saveFrame()
+o use File object for when people know what they're doing?
+X same issue occurs with pdf and creating graphics obj
+
+get initial version of pdf working
+X get rid of beginFrame/endFrame echo to recorders?
+X that way begin/end can just be where the recorder starts/stops?
+X recordRaw is really confusing..
+X when to use beginFrame/endFrame
+X is beginRaw/endRaw really needed?
+X seems to be a problem that it's an applet method
+X but then it's called on the g of the applet
+X but then it's the recorderRaw of that g that gets it called..
+X how to flush when the sketch is done
+X inside dispose method? explicit close?
+X call exit() at end of pdf apps? exit calls dispose on gfx?
+X beginRecord() and endRecord() so that record doesn't stop after frame?
+X enable PGraphicsPDF for inclusion
+X write documentation on images (they suck) and fonts (use ttf)
+
+
+0099 core
+X removed playing() method from PSound
+X integrate destroy() method from shiffman as dispose() in PSound2
+X ComponentListener is probably what's needed for resize()
+X make sure that components can be resized properly via size()
+X http://dev.processing.org/bugs/show_bug.cgi?id=209
+X or that it properly responds to a setBounds() call
+X calling size() elsewhere in the app doesn't quite work
+X A second call to size almost works.
+X The buffer apparently gets allocated and saveFrame saves the
+X new size but drawing appears to be disabled.
+X http://dev.processing.org/bugs/show_bug.cgi?id=243
+
+
+0098 core
+X change recordShapes() to just record() and recordRaw()
+X width, height set to zero in static mode
+X http://dev.processing.org/bugs/show_bug.cgi?id=198
+X probably only set when resize() is called, and it's not happening
+X be careful when fixing this, bugs 195/197 were a result:
+X http://dev.processing.org/bugs/show_bug.cgi?id=195
+X http://dev.processing.org/bugs/show_bug.cgi?id=197
+X PSound.play() won't play the sound a 2nd time
+X (have to call stop() first)
+X http://dev.processing.org/bugs/show_bug.cgi?id=208
+
+
+0097 core
+X no changes, only export to application stuff
+
+
+0096 core
+X set applet.path to user.dir if init() is reached and it's not set
+X add DISABLE_DEPTH_TEST to PGraphics3
+X need to document this somewhere
+X also need to add to PGraphicsGL
+X access logs are being spammed because openStream() gets a 404
+X the default should be to check the .jar file
+X openStream() doesn't work with subfolders
+X http://dev.processing.org/bugs/show_bug.cgi?id=218
+X screwed up movie loading paths (quick fix)
+X http://dev.processing.org/bugs/show_bug.cgi?id=216
+X additional cleanup in the Movie class
+X make path thing into getPath() or something?
+X sketchPath(), dataPath(), savePath(), createPath()
+X applet shouldn't be resizing itself
+X opens at correct size, then makes itself small, then large again
+X setup() mode apps often don't open at the correct placement
+X because of their resizing
+X check into bug where applet crashing if image not available
+X probably need to add a hint() to make things not halt
+X loadBytes() and openStream() et al need to return null
+X loadImage() can too, but print an error to the console
+X "not available in P3D" should read "OPENGL" in opengl lib
+X keypressed ref: repeating keys
+X also remove "no drawing inside keypressed"
+X text block wrap problem with manual break character (\n)
+X http://dev.processing.org/bugs/show_bug.cgi?id=188
+
+draw mode issues
+X when run externally without a draw, applets will exit immediately
+X when run internally (no code folder or .java files) will just wait
+X shouldn't quit draw mode apps immediately
+X otherwise something gets drawn then the applet exits
+X should instead use exit() when they need to exit
+X NullPointerException when no draw()
+X http://dev.processing.org/bugs/show_bug.cgi?id=210
+X window closing immediately with library imports
+X http://dev.processing.org/bugs/show_bug.cgi?id=204
+X check into loadImage() with jars bug, very frustrating
+o when using loadImage() on a jar, turn off "no cache" option?
+X image no load halts the program (rather than returning null)
+X note in the reference: png images work with java 1.3+
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=WebsiteBugs;action=display;num=1125968697
+X add bug re: gif image break missing to revisions.txt
+X http://dev.processing.org/bugs/show_bug.cgi?id=217
+
+image pile
+X get loadImage() to work properly with data folder
+X should probably use the code from loadStream
+X and the url stuff should be an alternate method altogether
+o loadImage() seems to be caching everything from the jar
+X http://java.sun.com/developer/technicalArticles/Media/imagestrategies/index.html
+o make a note of how to disable this
+o http://processing.org/discourse/yabb/YaBB.cgi?board=Programs;action=display;num=1078795681
+o bizarre image loading error with c_Rollover.zip
+X couldn't find/replicate this
+o read uncompressed tiff
+X read uncompressed tga files.
+X http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_Software;action=display;num=1081190619
+X http://processing.org/discourse/yabb/YaBB.cgi?board=Tools;action=display;num=1066742994
+o updated png encoder
+o http://processing.org/discourse/yabb/YaBB.cgi?board=Syntax;action=display;num=1083792994
+
+older stuff, no longer an issue
+o don't cache stuff from loadStrings and others
+o mac java vm won't give up old version of file
+o or use setUseCaches(false)
+o too many push() will silently stop the applet inside a loop
+X allow save(), saveFrame() et al to properly pass in absolute paths
+X (so that it doesn't always save to the applet folder)
+X could require that save() takes an absolute path?
+X loadImage must be used inside or after setup
+X either document this and/or provide a better error message
+X http://processing.org/discourse/yabb/YaBB.cgi?board=Programs;action=display;num=1060879468
+X expose function to write tiff header in PImage (advanced)
+X helps with writing enormous images
+X tag release 93 (francis thinks it's rev 1666)
+
+
+0095 core
+X undo the fix that causes the width/height to be properly set
+
+
+0094 core
+X fix bug that was causing font sizes not to be set on opengl
+X http://dev.processing.org/bugs/show_bug.cgi?id=174
+X apply fix from toxi to make targa files less picky
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1127999630
+X "folder" has been renamed to "path" to match savePath().
+X added "dataPath" to return the full path to something in the data folder
+X savePath should maybe be appletPath or sketchPath
+X because can be used for opening files too
+X (i.e. if needing a File object)
+X width, height set to zero in static mode
+X probably only set when resize() is called, and it's not happening
+X g.smooth is always false in opengl
+X http://dev.processing.org/bugs/show_bug.cgi?id=192
+
+o triangleColors are different because they're per-triangle
+o as opposed to per-vertex, because it's based on the facet of the tri
+X make vertexCount etc properly accessible in PGraphics3
+X so that people can do things like the dxf renderer
+X also have a simple way to hook in triangle leeches to PGraphics3
+X this exists, but needs to be documented, or have accessors
+
+
+0093 core
+X upgrade jogl to a newer rev to fix osx "cannot lock" issues
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1118603714
+X http://192.18.37.44/forums/index.php?topic=1596.msg79680#msg79680
+X faster blur code contributed by toxi
+X filter(ERODE) and filter(DILATE) contributed by toxi
+o textAscent() should probably be g.textAscent instead
+o more like textLeading() etc
+X nope, because it requires grabbing the font metrics and other calculations
+X bezierDetail, curveDetail made public
+X added textMode(SHAPE) for OPENGL
+X error message saying that strokeCap and strokeJoin don't work in P3D
+X textMode(SHAPE) throws ex when drawing and font not installed
+X fix a bug with filename capitalization error throwing
+X add NO_DEPTH_TEST to PGraphics3
+X java 1.4 code snuck into PApplet, causing problems on the mac
+X http://dev.processing.org/bugs/show_bug.cgi?id=146
+X prevent PGraphics.save() from inserting a file prefix
+X so that people can use absolute paths
+X or add a version that takes a file object
+
+nixed or fixed in previous releases
+X textMode(SCREEN) having issues on Mac OS X
+X seem to be problems with updatePixels() on the mac
+X appears to run asynchronously
+X move zbuffer et al into PGraphics so that people don't have to cast to P3
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Contribution_3DOpenGL;action=display;num=1116978834
+o noLoop() is behaving strangely
+o http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1116002432;start=0
+
+
+0092 core
+X rle-compressed tga save() method added by toxi
+X also version that only saves RGB instead of ARGB
+X proper/consistent api to access matrices in PGraphics/PGraphics3
+X first use loadMatrix(), then m00, m01 etc
+X find the post on the board and make a note of this
+X proper api for access to Graphics2D object in PGraphics2
+X just add the current "g2" thing to the faq
+X and make a note of it on the suggestions board
+X vars like cameraX etc need to be in PGraphics
+X otherwise g.xxxx won't work
+X how far should this go? vertices etc?
+X vertices not included because switching to triangleImpl and lineImpl
+X fix for copy() in java2d to make things a little speedier
+X make PApplet.main() for java 1.3 friendly (Color class constants)
+X remove call to background() in PGraphics2
+o change PGraphics to PGraphics2
+o or not, because PGraphics has all the base stuff for 3D
+o change PGraphics2 to PGraphicsJava or PGraphicsJava2D
+o maybe wait until the new shape stuff is done?
+X move font placement stuff back into PGraphics?
+X figure out how to get regular + java fonts working
+X use that do drive how the api is set up
+X optimize fonts by using native fonts in PGraphics2
+X especially textMode(SCREEN) which is disastrously slow
+X in java2d, can quickly blit the image itself
+X this way, can isolate it for gl too, which will use glBitmap
+X danger of this setup is that it may run much nicer for the author
+X i.e. with the font installed, and then super slow for their users
+X add "smooth" as a field inside the font file
+X and when smooth field is set, make sure JAVA2D enables smoothing
+X since otherwise smooth() has to be called for the whole g2
+X rob saunders contributed a fix for a bug in PImage.copy()
+X the wrong boundaries were being copied in the code
+X fix bug where noLoop() was waiting 10 secs to call exit()
+X add ability to draw text from the current text position
+
+
+0091 core
+X change to synchronization to hopefully fix some update issues
+X curveVertex() problem in P2D when > 128 points fixed
+_ http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1115856359;start=0
+X for present mode, need to set a default display
+X currently crashes if only --present is specified w/o --display
+o make the 1.4 code in PApplet load via reflection
+X doesn't appear necessary with 1.3 applets
+o or is some of the stuff usable in 1.3 but not all?
+o ie. the device config classes exist but not the set full screen method
+X currently some bugs in the main() because it's not sizing applets
+X if running in present mode it works ok
+X but that also needs its display set.. argh
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1115834600;start=0
+X add exit() function to actually explicitly quit
+X scripts will just require that people include exit at the end
+X esc should kill fullscreen mode (actually now it just quits anything)
+X can a key handler be added to the window? not really
+X add an escape listener to the applet tho.. but will it work with gl?
+X how can this be shut off for presentations?
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1114027594;start=0
+X present mode wasn't reading the stop button color
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Suggestions;action=display;num=1116166897;start=0
+X cleaned up the createFont() functions a little
+X java 1.3 required message isn't clickable
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1117552076
+
+
+0090 core
+X added arraycopy() function that calls System.arraycopy()
+X also the useful shortcut fxn
+
+
+0089 core
+X no changes since 88
+
+
+0088 core
+X createFont crashes on verdana (win2k)
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1115258282;start=0
+X made ceil(), floor(), and round() return ints instead of floats
+X fix for PSound: Unsupported control type: Master Gain
+X just shuts off the volume control
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1115467831;start=0
+
+cleared out / completed in previous releases
+X typed version of expand() and contract()
+o fishwick bug with text() and shapes
+o ellipses no longer completed when g.dimensions = 2 or 3,
+o or not even drawn.. what a mess.
+X go through and figure out what stuff to make public
+o depth testing of lines vs text is problematic
+o probably need to patch in an older version of the line code
+o use depth()/noDepth() to handle depth test
+X on exceptions, use die to just kill the applet
+X make the file i/o stuff work more cleanly
+X if people want to use their own file i/o they can do that too
+o this could also be contributing to the hanging bug
+X static applets need to be able to resize themselves on 'play'
+X figure out what to do with static apps exported as application
+X needs to just hang there
+o scripts (w/ no graphics) will need to call exit() explicitly
+o actually.. just override the default draw() to say exit()
+X may need a fileOutput() and fileInput() function
+X to take care of exception handling
+o or maybe scripts are just handled with a different method? (yech)
+o or maybe setup() can actually throw and Exception?
+o but that's inserted by the parser, and hidden from the user?
+o implement size(0, 0) -> just doesn't bother doing a frame.show();
+o too abstract, just have draw() call exit by default
+o so if nothing inside draw, just quits
+o make properly exit after things are finished
+o still some weirdness with thread flickering on the mac
+o and frenetic display updates on the pc
+o move really general things out of PConstants (X, Y, Z..) ?
+X add something to PApplet to have constants for the platform
+o needed for error messages (don't talk about winvdig on mac)
+X and also useful for programs
+X bring screen space and font size settings back in to PGraphics
+X causing too much trouble to be stuck down in PFont
+
+
+0087 core
+
+fixed in previous releases
+X The PushPop example in Transformations is not working
+X with lights() callled
+X The transparency of the Rotate3D example in Translformations
+X is not as expected
+X lighting totally sucks (both PGraphics3 and PGraphicsGL)
+X bring in materials for opengl as well?
+X don't include a class, just make it similar to the light functions
+X sphere() and box() should set normals and take textures
+X background color seems to be wrong?
+X check this once lighting actually works
+X printarr() of null array crashes without an error
+X actually, errors from many crashes not coming through on the mac?
+
+
+0086 core
+X java 1.4 getButton() was inside the mouse handler
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1114147314;start=3
+X color() doesn't work properly because g might be null?
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1114518309;start=0
+X textMode(RIGHT) etc causing trouble.. tell ppl to use textAlign()
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=Syntax;action=display;num=1114219121;start=4
+X saveFrame with a filename still causing trouble:
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1114097641;start=0
+X fov should be in radians
+X present mode not working on macosx 10.2?
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1114381302;start=0
+X ex on endshape if no calls to vertex
+X http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1113940972
+X is camera backwards, or staying fixed and moving the scene?
+X camera() is broken, should be ok to call it at beinning of loop
+X end of lookat might be backwards
+X or endCamera might be swapping camera and cameraInv
+X beginCamera also grabs it backwards
+
+
+0085 core
+X camera() was missing from PGraphics
+X some tweaks to openStream() for loading images and less errors
+X basic clipping in P3D from simon
+
+
+0084 core
+X fixed create font / incremented font file version number
+X simon lighting fixes
+X added simon's lighting docs to lights() fxn in javadoc
+X set default stroke cap as ROUND
+X otherwise smooth() makes points disappear
+X hack for text with a z coordinate
+
+
+0083 core
+X fix double key events
+X fix mrj.version security error on the pc
+X set() fixes for PGraphics2 and setImpl inside PGraphics
+X remove angleMode (also from PMatrix classes)
+X remove/rename postSetup() stuff from PGraphics/PApplet
+X camera(), perspective(), ortho()
+X matrix set by the camera on each beginFrame
+X push/pop are now pushMatrix/popMatrix
+o get PGraphics.java engine working again
+
+lighting stuff
+X make fill() cover ambient and diffuse
+X provide separate call for ambient to shut it off
+o why does diffuse just mirror fill()?
+o seems to cover just diffuse, not ambient_and_diffuse like fill
+o maybe fill() should set diffuse, and sep call to ambient() sets ambient?
+X removed it
+X move dot() to the bottom w/ the other math
+
+already done
+X remove PMethods as actual class, use recordFrame(PGraphics)
+X size(200, 200, "processing.illustrator.PGraphicsAI");
+
+api questions
+o image(String name) and textFont(String name)
+o do we change to font(arial, 12) ?
+X remove angleMode() ?
+X be consistent about getXxx() methods
+X just use the variable names.. don't do overkill on fillR et al
+X or just what functions are actually made public
+X is fillRi needed? it's pretty goofy..
+X how to handle full screen (opengl especially) or no screen (for scripts)
+
+tweaking up simong light code
+o what's up with resetLights?
+o add PLight object to avoid method overflow
+o preApplyMatrix, invApplyMatrix?
+o applyMatrixPre and applyMatrixIn
+o rotateXInv is ugly..
+o irotateX?, papplyMatrix?
+
+wednesday evening
+X expose api to launch files, folders, URLs
+X use with/in place of link()
+X call it open()
+X what to call firstMouse
+X implement rightMouse?
+X yes, mouseButton = LEFT, CENTER, or RIGHT
+X error when running on 1.1...
+X You need to install Java 1.3 or later to view this content.
+X Click here to visit java.com and install.
+X make inverseCamera into cameraInv
+X fix messages referring to depth()
+X route all of them through a single function rather than current waste
+X fix bezierVertex() in P3D for newer api
+
+wednesday late
+X track loadImage() with filenames that are inconsistent
+X really a problem with the ves61r kids
+X i.e. mixed case filename in sketch is different in windows
+X but when uploaded to a unix server causes a serious problem
+X use canonicalPath to flag possible problems
+X http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1096508877;start=5
+o fix shapes in P3D (line loop, polygons, etc)
+o should we include a from and to for the directional light?
+X no, cuz it doesn't do much really..
+X fromX-toX etc is all that's different
+
+thursday day
+X set modelview to camera on endCamera
+X add ortho() and perspective() to PGraphics.java
+
+thursday evening
+o textMode(ALIGN_LEFT) etc, should make sure that left/center/right not used
+X though since have to change to LEFT, should be easy to switch
+
+friday night
+o should toInt('5') return the ascii or the char?
+X since (int) '5' returns the ascii, that's what it does
+X made a note in the PApplet reference
+
+text api
+X textMode ALIGN_CENTER _LEFT _RIGHT -> CENTER, LEFT, RIGHT ?
+X use built-in font if available? yes
+o text() with \n is semi-broken
+X does the font or PApplet control the size? (the font, ala java)
+X without setting the font, SCREEN_SPACE comes out weird
+o move SCREEN_SPACE into ScreenFont() class?
+o probably not, casey thinks screen space text is prolly more useful
+o that way can clear up some of the general confusion in the code
+X textFont with a named font can use the renderer/os font
+X illustrator api can get the ps name from the java font name
+X since it's associated with the font file.. wee!
+X for postscript, can grab the real font
+o altho problem here is that really the fonts just need a name
+o since needs to render to screen as well
+o font has to be installed to get psname
+X fine because why would you embed a ps font that you don't have?
+o need to resolve SCREEN_SPACE vs OBJECT_SPACE
+o can this be auto-detected with noDepth()?
+o how does rotated text work?
+o PFont.rotate(180) rotate(PI)
+o or can this be detected from the matrix?
+X don't use pixels to do screen space text inside PFont
+X add a function in PGraphics for direct pixel image impl
+X store the font name in the vlw font file (at the end)
+o could include multiple names for multi platforms
+X get text impl stuff working properly
+o look into fixing the texture mapping to not squash fonts
+o NEW_GRAPHICS totally smashes everything
+
+friday postgame
+X implement createFont()
+X with a .ttf does a create font internally (1.3+ only)
+X although the images aren't populated
+X until a P2D/P3D/OPENGL tries to draw them, which triggers it
+X but if PGraphics2, just uses the built-in font
+X also works for font names and just creating them
+X if font name doesn't end with otf or ttf, then tries to create it
+X change objectX/Y/Z to modelX/Y/Z
+X PFont.list() to return string list of all the available fonts
+X probably not a mode of use that we really want to encourage
+X actually important because the whole graphicsdevice crap is silly
+X and we need a 1.1 versus 1.3/1.4 version
+X implement printarr() as println() ?
+X actually deal with all the array types.. oy
+X should nf() handle commas as well?
+X just add a basic nfc() version for ints and floats
+o yes, and add nf(int what) so that non-padded version works
+o but don't put commas into the zero-padded version
+o make nf/nfs/nfp not so weird
+o nf(PLUS, ...) nf(PAD, ...) nfc(PLUS, ...)
+X unhex was broken for numbers bigger than 2^31
+
+saturday late afternoon
+X fix bug with openStream() and upper/lowercase stuff
+X do a better job of handling any kind of URLs in openStream()
+
+sunday morning
+X incorporate simon's new lighting code
+
+
+0082 core
+X make jdkVersion, jdkVersionName, platform, platformName variables
+X additional note about screen sizes and displays
+X sto instead of stop in present mode
+X appears that opengl libraries weren't correctly added in 81?
+X requestFocus() now called on gl canvas
+X basic lights now work by default
+
+
+0081 core
+X background(PImage) now works in opengl
+X when running externally, applets don't always get placed properly
+X if size is never set, then doesn't always layout
+X problem is in gl and in core, and is inconsistent
+X move more logic for layout into PApplet.. maybe a static method?
+X this way can avoid duplicating / breaking things
+o what is the stroked version of a sphere? a circle?
+X write list of params that can be passed to PApplet
+o document in the code a note about how size() et al place themselves
+X saveFrame was double-adding the save path because of save() changes
+
+size(200, 200, P3D) - createGraphics and placement issues
+X make pappletgl work back inside papplet
+X and then size(300, 300, DEPTH) etc
+X get rid of opengl renderer menu
+o otherwise hint() to use the p5 renderer instead of java2d
+X applet placement is screwy
+X how to force PGraphics() instead of PGraphics2()
+X size(300, 200, P2D);
+X size() doing a setBounds() is really bad
+X because it means things can't be embedded properly
+o applets on osx (and windows) sometimes show up 20 pixels off the top
+X how to shut off rendering to screen when illustrator in use?
+X need size(30000, 20000) for illustrator, problem in papplet
+X size(30000, 20000, ILLUSTRATOR)
+X make Graphics2 et al load dynamically using reflection
+X can this be done with g2 and if exception just falls back to g1?
+X this way people can remove g1 by hand
+o size() that changes renderer will throw nasty exception in draw()
+X or maybe that's ok? document that no changing renderers?
+X take a look to see what needs to happen to get PAppletGL merged in
+X i.e. can i just extend GLCanvas?
+
+present mode
+o call present() from inside the code?
+o that if applet is 500x500, centers on a 800x600 window
+X no, that's nasty... use --present to launch in present window
+X though how do you get the screen size?
+X screen.width and screen.height? - yes
+X write java 1.4 code for full screen version of PApplet
+X this might be used for presentation mode
+X proper full screen code for present mode
+X why do mouse motion events go away in full screen mode
+X or with a Window object
+X use screen manager to run present mode properly
+X set both versions to require java 1.4
+X change the Info.plist inside macosx
+X and add something to PdeBase to make sure that it's in 1.4
+X running present mode with a bug in the program hoses things
+X make sure the program compiles before starting present mode
+
+
+0080 core
+X PApplet.saveFrame() is saving to sketch folder, PApplet.save() is not
+X PApplet.save() will save to the applet folder,
+X but PImage.save() or PGraphics.save() will save only to the current
+X working directory, usually the Processing folder.
+X removed static version of mask() from PImage
+X no more PImage.mask(theImage, maskImage)
+X just use theImage.mask(maskImage)
+X PImage.filter()
+X maybe use quasimondo's gaussian blur code?
+X http://incubator.quasimondo.com/processing/gaussian_blur_1.php
+o filter() on subsections? yes, in keeping with rest of api
+X no, in keeping with getting shit done
+X BLUR - write simple blur
+X how does photoshop handle this?
+X BLUR - add gaussian blur
+X email re: credit/attribution and descrepancy between algos
+X forgot to mention the line hack to get points working in 78
+X implemented PGraphicsGL.set(x, y, argb)
+X implement PGraphicsGL.set(x, y, PImage)
+X blend, copy, filter all implemented for opengl
+X copy(Pimage, x, y) has become set(x, y, PImage)
+X textMode -> textAlign
+X ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT -> LEFT, CENTER, RIGHT
+X textSpace -> textMode
+X NORMAL_SPACE -> NORMALIZED, OBJECT_SPACE -> OBJECT
+X text in a box is broken (at least for PGraphics2)
+o check to see if it's a rounding error with width()
+o get text rect working again (seems to be in infinite loop)
+X nope, was just that the space width wasn't being scaled up properly
+X clean up the javadoc so no more errors
+X change mbox to PFont.size?
+o make width() return values based on natural size?
+X not a great idea.. plus java2d uses 1 pixel font for things
+X email simon re: lighting api
+X things are actually more on track than expected
+X camera is swapping colors in gl (on mac?)
+X in fact, all textures on mac were swapping colors
+X test this on windows to see if fixed
+X sphere x,y,z,r or box w,h,d.. need to make them consistent
+X goodbye sphere(x, y, z, r)
+o should available() be waiting() or something like that instead?
+o go through and see what functions (no pixel ops?) frame recorders should have
+X decided instead to use recordFrame(PGraphics)
+o remove SCREEN_SPACE altogether?
+X can't do this for now
+
+implemented in 79
+X make sure arc goes in the right direction that we want it to
+X (make sure that PGraphics3 goes the same direction)
+
+
+0079 core
+X no changes to core in this release
+
+
+0078 core
+X text fixes
+X lines were getting horizontally mashed together
+X lines also getting vertically smashed together
+X make a note of the change to font.width()
+X backwards rects and backwards ellipses weren't properly drawn
+X code now compensates for negative widths or swapped x1/x2
+X what to do about backwards images
+X imageMode() wasn't being set properly
+X fix noLoop() not properly running
+X If noLoop() is called in setup(), nothing is drawn to the screen.
+X also fix redraw() to include interrupt() again
+X loadPixels throwing NPEs
+X fixes to SCREEN_SPACE text not being sized properly
+X loadPixels()/updatePixels() on screen space text (ouch)
+X get SCREEN_SPACE text working again
+X patch in newer jogl.. too many BSODs
+X saveFrame seems to be broken
+X fixed for PGraphics2
+X fixed for PGraphicsGL
+X also implemented loadPixels/updatePixels for gl
+X fix tint() with color and alpha for PGraphics2
+X alpha() colors are inverted (white is opaque.. doesn't make sense)
+X should we swap this around? no - this is how photoshop works
+X fix arc
+X get() is back
+X set camera.modified so that it draws properly
+X it's annoying not having a copy() function inside PImage
+X formerly get() with no params
+o clone throws an exception
+o PImage constructor that takes itself?
+o PImage copy = new PImage(another);
+X got rid of CONCAVE_POLYGON and CONVEX_POLYGON
+X hack for points to work in opengl, but still not working broadly
+X work on filter() functions
+X POSTERIZE - find simple code that does it?
+X there must be a straightforward optimized version of it
+o EDGES - find edges in casey's example is differen than photoshop
+o which version do people want with their stuff
+X edges filter removed
+X several fixes to Movie and Camera to work with the new gfx model
+X PImage.get(x, y, w, h) had a bug when things went off the edge
+X set defaults for strokeCap and strokeJoin
+X get() and gl images were broken for screen sizes less than full size
+X fix arcs, were badly broken between java2d and pgraphics
+X look at curve functions more closely
+X should we switch to curveVertex(1,2,3) (ala curveto)
+X because some confusion with mixing types of curves
+o make sure we don't want curveVertices(1,2,3,u,v)
+o also make test cases so that java2d and java11 behave the same
+X implement PGraphics2.curveVertex()
+X updatePixels() not setting PApplet.pixels
+X make loadPixels in PGraphics ignored, and put it in PApplet
+X made loadStrings() and openStream(File) static again
+X test loadPixels()/updatePixels()/saveFrame() on the pc
+X better, just assume that they need the endian swap
+X fixed draw mode apps for opengl
+X (gl was missing a beginFrame)
+X pmouseX, pmouseY are not working in OpenGL mode
+X (as they are working in Processing mode)
+
+o screenX/Y aren't properly working for 2D points against a 3D matrix
+o (ryan alexander rounding bug)
+o Just to clarify, it works completely correctly with rounding
+o screenX/Y and also using the 3 arg version of translate -
+o ie translate(hw,hh,0) instead of just translate(hw,hh).
+X no longer an issue because moving to 2D and 3D modes
+o PImage: remove the static versions of manipulators?
+o probably not, because they're inherited by PApplet
+o i.e. mask(image, themask);
+X no PImage needed b/c PGraphics is a PImage
+o colorMode(GRAY) to avoid stroke(0) causing trouble?
+o or maybe get rid of stroke(0)? hrm
+
+
+0077 core
+X bring back pmouseX/Y using a tricky method of storing separate
+X values for inside draw() versus inside the event handler versions
+X debug handling, and make firstMouse public
+X explicitly state depth()/nodepth()
+X don't allocate zbuffer & stencil until depth() is called
+X arc with stroke only draws the arc shape itself
+X may need a 'wedge' function to draw a stroke around the whole thing
+X only allocate stencil and zbuffer on first call to depth()
+X this will require changes to PTriangle and PLine inside their loops
+X try running javadoc
+X die() may need to throw a RuntimeException
+o call filter() to convert RGB/RGBA/ALPHA/GRAY
+o cuz the cache is gonna be bad going rgb to rgba
+X don't bother, people can re-create the image or set cache null
+X fix font coloring in PGraphics2
+X fix tint() for PGraphics2
+X get text working again
+X partially the problem is with ALPHA images
+X how should they be stored internally
+X also colored text, requires tint() to work properly
+X move textMode and textSpace back out of PFont
+X use die() to fail in font situations
+X can't, just use a RuntimeException
+
+covered in previous
+X before graphics engine change, attach jogl stuff
+X need to try jogl to make sure no further changes
+X and the illustrator stuff
+o massive graphics engine changes
+o move to new graphics engine
+o test with rgb cube, shut off smoothing
+o make sure line artifacts are because of smoothing
+o implement 2x oversampling for anti-aliasing
+o renderers can plug in:
+o at direct api level
+o taking over all color() functions and vertex collection
+o at endShape() level
+o where vertices are collected by core and blit on endShape()
+o (takes polygons and lines)
+o at post tesselation level
+o takes only line segments and triangles to blit (dxf writer)
+o api for file-based renderers
+o need to work this out since it will affect other api changes
+o size(0, 0) and then ai.size(10000, 20000)
+o size 0 is code for internal to not show any window
+o saveFrame(PRenderer) or saveFrame("name", PRenderer)
+o saveFrame gets called at the beginning of loop()
+o or is just a message to save the next frame (problem for anim)
+X vertices max out at 512.. make it grow
+X add gzipInput and gzipOutput
+X light(x, y, z, c1, c2, c3, TYPE)
+X also BLight with same constructor, and on() and off() fxn
+X make sure applet is stopping in draw mode
+X loadImage() is broken on some machines
+X hacked for a fix in 72, but need to better coordinate with openStream()
+
+postscript
+X pushing all intelligence down into class that implements PMethods
+o keep hints about type of geometry used to reconstruct
+o no special class, just uses public vars from PGraphics
+o how to hook into curve rendering so that curve segments are drawn
+o maybe lines are rendered and sorted,
+o but they point to an original version of the curve geometry
+o that can be re-rendered
+o also integrate catmull-rom -> bezier inverse matrices
+o even with the general catmull-rom, to render via ai beziers
+
+api changes
+X removed circle.. it's dumb when ellipse() is in there
+X (it's not like we have square() in the api)
+X arcMode is gone.. just uses ellipseMode()
+X save tga and tif methods are static and public
+X imageMode(CORNER) and CORNERS are the only usable versions
+X alpha(PImage) is now called mask() instead
+X already have an alpha() function that gets alpha bits
+X on start, mouseX is 0.. how to avoid?
+X use firstMouse variable.. figure out naming
+X get frame recording working
+X not tested, but at least it's there
+
+image stuff
+o could also do PImage2, which would need a getPixels() before messing w/ it
+o bad idea, distinction not clear
+o even in java 1.1, could use regular java.awt.Image and require getPixels()
+o -> 1.1 wouldn't help anything, because needs pixels to render, oops
+X the updatePixels() in PGraphics has to be overridden (from PImage)
+X to make itself actually update on-screen
+X actually, should be no different than the check_image function
+X PGraphics2 and PGraphicsGL will need loadPixels() to be called
+X in order to read pixels from the buffer
+X loadPixels() and updatePixels() prolly should be shut off in opengl
+X make people use get() instead to grab sub-images
+X PGraphicsGL.copy() needs to be overridden.. use glDrawBitmap
+o loadImage() needs to handle 1.1 vs 1.3 loading
+o set image.format to be BUFFERED? no.. just use RGBA always
+o have a flag to always use the cache, i.e. with BufferedImage
+o turn that off when someone modifies it (nope, no need to)
+X PImage.getPixels(), updatePixels(), updatePixels(x, y, w, h),
+o PImage.setPixels(int another[]);
+X imageMode(CENTER) is weird for copy() and updatePixels()
+X perhaps copy() and get() ignore imageMode and use xywh or x1y1x2y2?
+X or disallow imageMode(CENTER) altogether?
+o in java 1.3, getPixels() can call getRGB() via reflection
+o cache.getClass().getName().equals("BufferedImage")
+X readPixels/writePixels?
+X has to happen, since this is so fundamental to gl as well
+X loadImage in 1.3 leaves pixels[] null (not in 1.1)
+X 1.3 plus gl is a problem, since conflicting caches
+X gl has no need for a bufferedimage tho
+X so maybe checks to see if the cache is a BufferedImage
+X if it is, calls getPixels to set the int array
+X then replaces cache with glimageache
+X pappletgl loadimage could take care of this instead
+X calls super.loadImage(), if cache != null, proceed..
+X this is prolly a mess
+X PImage.getPixels() and PImage.getPixels(x, y, w, h) ->
+X (the xywh version still allocates the entire array, but only updates those)
+X only needed for java2d
+X not (necessarily) needed when loading images,
+X but definitely needed when setting pixels on PGraphics
+X PImage.updatePixels() and PImage.updatePixels(x, y, w, h)
+X (this is actually just setModified)
+X in opengl, marks all or some as modified
+X so next time it's drawn, the texture is updated PGraphicsGL.image()
+X in java2d, updates the BufferedImage on next draw
+X can't use regular getPixels() on PGraphics, because its image isn't 'cache'
+X also, the cache may be used to draw the whole surface as a gl texture (?)
+X not a problem for the main PGraphics, but for any others created to draw on
+
+opengl
+X make light() functions actually do something in PGraphicsGL
+X box() and sphere() working again
+X make opengl work in draw mode
+X set initial size using --size=
+X color channels seem to be swapped on windows in image example
+X check on the mac to see what it looks like
+
+X default to single byte input from serial port
+X and add serial.setBuffer() for message length as alternative
+X or serial.setDelimiter() to fire message on delim
+X named it bufferUntil();
+
+
+0076 core
+X no changes, only launcher issues
+
+
+0075
+X textureMode(NORMAL_SPACE) screws up the image() command
+X image() appears to require IMAGE_SPACE to function properly.
+X added focusGained() and focusLost()
+X lots of changes to internal naming of vars
+X screenX(x, y) and screenY(x, y) added for noDepth()
+X add TRIANGLE_FAN
+X eyeX, eyeY etc have been renamed cameraX/Y/Z, and cameraNear/Far
+X modify targa and tiff writing routines to break into header writing
+X writeTIFF, writeHeaderTIFF, writeTGA, writeHeaderTGA
+X MAJOR CHANGE: RGBA becomes ARGB for accuracy
+o uv coords > 1 shouldn't clamp, they should just repeat ala opengl
+o actually i think opengl has a setting for it
+o remove need to use depth() at the beginning
+X need only be set once
+X pmouseX is broken again
+X remove pmouseX/Y altogether
+X maintain things a bit different
+o email the beta@ list to see how people are using pmouseX
+X changed PMovie.length to PMovie.duration
+X move around/simplify loadImage() inside PApplet
+X working to add more die() statements inside PApplet
+o can ALPHA fonts work using the other replace modes?
+
+fixed in previous releases
+X text stuff
+X text() with alignment doesn't work for multiple lines
+X don't change the size of a font when in screen space mode
+X patch rotated text (from visualclusto) into bfont
+X what sort of api? textSpace(ROTATED) ?
+X rotated text has a bug for when it goes offscreen
+
+opengl
+X why is the thing hanging until 'stop' is hit?
+X what happens when stop is hit that sets it free?
+X (at what point does it start working properly?)
+X cache needs to also make things a power of 2
+X if images are already a power of 2, then needn't re-alloc
+X cacheIndex needs to be set to -1 when the image is modified
+X or maybe have a modified() function?
+X debug why certain spots are having errors (see 'problem here' notes)
+X INVALID_OPERATION after drawing lines for cube
+X fix noLoop bug
+X remove errors when drawing textures
+X reverse y coordinates
+X make play button un-highlight with opengl
+X also make window move messages work properly
+X very necessary, since opens window at 100x100
+X problem was the threading issues
+X bring back renderer menu
+X reading/saving pref for opengl renderer
+X remove cameraMode(PERSPECTIVE) on each frame
+X why is the first one failing?
+X still threading issues with running opengl
+X threading really horks up dual processor machine..
+X first run hangs until quit
+X though doesn't seem to replicate when p5 is restarted
+X make sure background() gets called at least once with opengl
+X otherwise screen never actually updates
+X beginFrame() around setup()
+X draw mode stuff happens inside setup..
+o or maybe need to get better at size() inside of draw() ?
+X make this consistent with the regular PApplet
+X otherwise things are going to be weird/difficult for debugging
+
+
+0074 core
+X removed zbuffer precision hack in PLine to improve z ordering
+X no longer set g.dimensions = 3 when using vertex(x, y, 0)
+
+
+0073 core
+X tweak to fonts to use TEXT_ANTIALIAS because of macosx @#$(*&
+X loadImage() is broken on some machines
+X hacked for a fix in 72, but need to better coordinate with openStream()
+
+
+0072 core
+X make m00, m01 etc public
+X hack to make loadImage() work
+X cache settings are ignored, may be slow as hell
+X make hints[] no longer static
+X they weren't properly resetting
+
+
+0071 core
+X properly swap alpha values when lines need to be rendered backwards
+X make cursor() commands public
+X ltext and rtext for screen space stuff
+X ltext is broken when it goes y < 0 or y > height
+X ltext & rtext completely working
+X make sure font creator is making fonts properly fixed width
+X probably not using java charwidth for the char's width
+X probably wasn't using textFont() properly
+X now that it's actually a key, should it be a char? (what's keyChar?)
+X that way println(c) would work a little better..
+X libraryCalls() not properly working for pre, post, or draw()
+o image(myg, x, y) doesn't work but image(myg, x, y, w, h) does
+o (image kind prolly not set right and so image() gets pissy)
+o http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1091798655
+
+text fixes
+X make text rect use rectMode for placement
+X if a word (no spaces) is too long to fit, insert a 'space'
+X move left/center/right aligning into the font class
+X otherwise text with alignment has problems with returns
+X could PFont2 be done entirely with reflection?
+X that way other font types can properly extend PFont
+o font char widths from orator were not fixed width
+o may just need to regenerate. if not, widths may be set wrong.
+
+
+0070 core
+o check ordering of split() in java vs perl for regexp
+X don't include empty chars in font builder
+X .vlw font files are enormous with full charset
+X check to see if the character exists before adding it to the font
+X fixed (unreported) problem with char lookup code
+o split() with multiple args (i think this is completed)
+X http://processing.org/discourse/yabb/YaBB.cgi?board=Syntax;action=display;num=1078985667
+X trim() not chop().. whups
+X random(5, 5) -> return 5, random(6, 4) return error
+X http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1083275855;start=0
+X use random.nextFloat() because it's faster
+X make grayscale image in p5
+X could be used with alpha() to properly set alpha values
+X made into filter(GRAYSCALE) and filter(BLACK_WHITE) functions
+X make g.depthTest settable as a hint
+X http://processing.org/discourse/yabb/YaBB.cgi?board=BugFixes;action=display;num=1096303102;start=0
+X #ifdef to remove client and server code as well
+X need to resolve issues between rendering screen/file
+X illustrator-based rendering needs to work for ars projects
+X screen may be 400x400 pixels, but file be 36x36"
+X launcher.cpp broke serial.. see versions in processing.notcvs
+X rewrite bagel code..
+X for this release, because it will break things along with the lib stuff
+X switch to PImage, PApplet, etc
+o bug in BImage.smooth() when resizing an image
+o http://processing.org/discourse/yabb/YaBB.cgi?board=BugFixes;action=display;num=1096303158;start=0
+X shut off the automatic gunzipping of streams, keep for fonts
+X fix for duplicated points in polygons that foiled the tesselator
+X http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1077819175
+X cleaned up texture() code between NEW/OLD graphics
+X not quite so much duplicated in cases etc.
+X lines: vertex coloring bug with my swap hack
+X http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1085348942
+X last vertex on LINE_LOOP fades out
+X http://processing.org/discourse/yabb/YaBB.cgi?board=BugFixes;action=display;num=1096303406;start=0
+X include values in PConstants for additional blend modes:
+X DIFFERENCE, MULTIPLY, SCREEN, OVERLAY, HARD_LIGHT, SOFT_LIGHT
+X include a lerp()? is there one in flash?
+X http://processing.org/discourse/yabb/YaBB.cgi?board=Programs;action=display;num=1083289030
+X should it be called lerp or mix?
+X acos, asin, atan, log, exp, ceil/floor, pow, mag(x,y,z)
+X color issues
+X doesn't work when outside a function:
+X color bg_color = color(255,0,0);
+X colorMode broken for red() green() etc
+X http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1068664455
+X add color(gray) and color(gray, alpha)
+X http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1089898189;start=0
+X http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_Software;action=display;num=1090133107
+o update() mode needs to be hacked in (?)
+X make 'online' a boolean
+X pass in args[] from main
+X angleMode(DEGREES) and angleMode(RADIANS)
+X http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_Software;action=display;num=1075507381;start=0
+X fixes to line and curve code
+X api to properly sense when applet has focus
+X add a 'focused' variable to the applet
+X code now in zipdecode, maybe just list this as a standard thing?
+X do applets know when they're stopped? stop? dispose?
+X would be good to set a param in p5 so that the thread dies
+X if people have other threads they've spawned, impossible to stop
+
+cleaning up
+X make bagel more usable as standalone
+X breakout BGraphics (have its own BImage)
+o breakout BApplet into BComponent ? (fix out-of-bounds mouse - doesn't)
+o opengl export / rendering mode
+o currently implemented, but somewhat broken
+o finish this once all the line code is done
+o make possible to use buzz.pl to create versions w/ stuff removed
+o build gl4java for java 1.4
+o separating of BGraphics and BApplet
+o change copyrights on the files again (to match ?)
+X loadStrings has a problem with URLs and a code folder
+o turned out to be a problem with firewall/antivirus software
+o http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1086551792
+o when running as an applet, need to loadStream from documentBase too
+o problem is that BGraphics has the loadStream code, not BApplet
+o new sphere code from toxi
+o already added a while back
+o http://processing.org/discourse/yabb/YaBB.cgi?board=Syntax;action=display;num=1067005325
+o sphere code needs only front face polygon
+o all triangles must be counter-clockwise (front-facing)
+X fix loadImage to be inside PApplet
+
+040715
+X saveFrame() to a folder horks things up if a mkdirs() is required
+X on macosx, this makes things hang; on windows it complains
+X http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1081706752;start=0
+X decide on whether to use PTools
+X decided against, since it doesn't help anything
+X and some functions need the applet object, so it's just annoying
+o i.e. move math functions into utility library
+o check what other functions require PGraphics to exist but shouldn't
+o look at BGraphics to see if setting an 'applet' could be used
+o then other than that, if no applet set, no connection to PApplet
+
+040716
+X change font api to not use leading() as a way to reset the leading
+X resetLeading and resetSize are the things
+X embed all available chars from a font, so japanese, etc works
+X http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_Software;action=display;num=1083598817;start=3
+X fix a bunch of font bugs regarding charsets and lookup
+X array operations: boolean, byte, char, int, float, String
+X expand/contract
+X append, shorten
+o shift/unshift
+o slice
+X splice
+X reverse
+X concat
+
+040717
+X make clone() into copy()
+X add a method BApplet.setPath() or something like that
+X use it to repair saveBytes, saveStrings, etc
+X put screenshots into their sketch folder
+o http://processing.org/discourse/yabb/YaBB.cgi?board=Syntax;action=display;num=1046185738;start=0
+X full casting operations on primitives and arrays of them
+X text(String text, x, y, width, height) // based on rectMode
+X textMode() for align left, center, right (no justify.. har!)
+X hex(), binary(), unhex(), unbinary()
+
+040725
+X fix array functions not returning a value
+
+040726
+X noiseSeed and randomSeed
+X http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_Software;action=display;num=1090749784;start=0
+
+040727
+X incorporated NO_FLYING_POO line/poly hack developed for axel
+
+040902
+X sort() should return an array, rather than sort in place
+X fix binary function, had wrong offset number
+X casey: i wan't able to get binary() to work at all:
+o Typography: Helix won't compile
+o works fine, just needs BFont -> PFont
+X standalone 'alpha' function for PImage (static methods for alpha fxns)
+X Image: Edge, Image: Blur: Alpha not set? The error is easier to see on Blur
+X turns out bounds checking wasn't working properly on colors
+
+040903
+X fix mouse/key events, make properly public for the package stuff
+X The biggest problem was the key and mouse functions not working.
+X Input: Mouse_Functions
+X Input: Keyboard_Functions
+X processing.net -> PClient, PServer
+X write client/server implementations for new-style api
+X basic test with old net server has things working fine
+
+040908
+X inputFile, outputFile, reader, writer commands
+X also loadStrings(File file)
+
+040913
+X printarr instead of print/println for arrays
+X println(Object o) conflicts with println(int a[])
+X but println(Object o) is very needed
+
+040919
+X loop/noLoop setup
+
+040920
+X make loop/noLoop work properly
+X fixes/changes to key and mousehandling
+X tab key not working?
+X http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1091853942;start=0
+X mousePressed, keyPressed, others.. queue them all
+X queue multiple times
+X http://processing.org/discourse/yabb/YaBB.cgi?board=Syntax;action=display;num=1079555200;start=0
+X strangeness with key codes on keyPressed
+X http://processing.org/discourse/yabb/YaBB.cgi?board=Syntax;action=display;num=1083406438;start=0
+X key codes not properly coming through for UP/DOWN/etc
+X had to bring back keyCode
+X http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1075138932;start=0
+X add redraw() function
+X call redraw() on the first time through (to force initial draw)
+X otherwise noLoop() in setup means no drawing happens at all
+
+040920 evening
+X defaults for PApplet and PGraphics are different
+o PGraphics has none.. PApplet has fill/stroke
+X actually not the case, only that wasn't calling decent superclass
+X set PImage.format as RGB by default?
+X this was problem with rendering an image from PGraphics on board
+X http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1091798655;start=0
+X http://processing.org/discourse/yabb/YaBB.cgi?board=Syntax;action=display;num=1080671926;start=0
+
+040921 morning
+X bug in get() that was removing the high bits (rather than adding)
+
+040921 evening
+X lots of work on libraries, figuring out PLibrary api
+
+040922
+X get library stuff debugged
+X port arcball and finish up dxf writer
+X beginCamera() no longer sets an identity matrix
+
+040925
+X make savePath() and createPath() accessible to the outside world
+X useful for libraries saving files etc.
+
+
+0070p8
+X sizing bug fix to fonts, they now match platform standards
+X however, *this will break people's code*
+X text in a box not written
+X make sure to note in the docs that text/textrect position differently
+o for this reason, should it be called textrect()?
+X font heights and leading are bad
+X get good values for ascent and descent
+X if ScreenFont subclasses PFont.. can that be used in textFont()?
+X check to make sure the tops of fonts not getting chopped in font builder
+
+
+0069 bagel
+X text(x, y, z)
+X fixed camera modes / replaced how isometric is handled
+X whoa.. BGraphics.screenX() et al had the camera stuff shut off
+X and that's what shipped in 67. shite.
+X need to get things fixed up properly so camera is properly set
+X ISOMETRIC was completely broken.. need to implement properly
+X also, the default camera is perspective
+X cameraMode(PERSPECTIVE) and cameraMode(ORTHOGRAPHIC) setup basic cameras
+X if the user wants a custom camera, call cameraMode(CUSTOM); before begin()
+X printMatrix() and printCamera() to output the matrices for each
+X more functions made static (loadStrings, loadBytes) that could be
+X print() commands in BApplet were among these
+X die() command to exit an application or just stall out an applet
+X die(String error) and die(String error, Exception e)
+X more documentation in comments for functions
+X chop() function that properly also handles nbsp
+X join() was handled weird
+X run nf() and nfs() on arrays
+X nfp() to show plus sign
+X toInt, toFloat, toDouble (nf is for toString.. inconsistent)
+o split() function splits strings instead of splitStrings()
+o ints() converts an array of strings/doubles/floats to an int array
+o split() should also use StringTokenizer
+o to do countTokens() and then stuff into an array
+o shave() or chomp() or trim() method to remove whitespace on either side
+o including unicode nbsp
+X min() and max() with three values were broken (now fixed)
+X http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1076804172
+X CONTROL wasn't properly set in BConstants
+X http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1077058788
+X macosx.. flickering several times on startup
+X fixed this, along with other sluggishness related threading issues
+X http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1073111031
+X bug with charset table on older fonts
+X index_hunt was look through the table, not what was in the font
+X http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1077475307;start=0
+X seems to be some difficult threading problems still present
+X fixed many threading issues across macosx and linux
+X side-porting changes
+X new(er) line code is not in the main 'processing'
+X making perlin non-static not in the main bagel
+X polygon stroking hack code from the end of 68
+X erikb found a bug inside split(), it would die on empty strings
+X http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1077664736
+X fixed it, also modified behavior of split() with a delimeter
+X previously, it would remove the final delimeter and an empty entry
+X but that's now disabled, since the split cmd is very specific
+X code from toxi to support .tga files in loadImage
+X http://processing.org/discourse/yabb/YaBB.cgi?board=Programs;action=display;num=1078459847;start=0
+X fix bug where single pixel points were ignoring their alpha values
+X static loadStrings and loadBytes aren't being added to BApplet
+X (the versions that use an inputstream)
+X added support for handling static functions in make.pl
+X threading is broken again on windows
+X windows needs a sleep(1) instead of the yield()
+X random(3) should be non-inclusive of the 3
+X http://processing.org/discourse/yabb/YaBB.cgi?board=Syntax;action=display;num=1079935258;start=5
+
+api changes
+X loadStream -> openStream for better consistency
+
+jdf
+X dynamic loading of code for setting cursor (removed JDK13 ifdef)
+X why aren't cursors working on the mac?
+X fix from jdf to just set size to 0,0
diff --git a/core/license.txt b/core/license.txt
new file mode 100644
index 000000000..16f1ad162
--- /dev/null
+++ b/core/license.txt
@@ -0,0 +1,456 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[ This is the first released version of the Lesser GPL.
+ It also counts as the successor of the GNU Library Public
+ License, version 2, hence the version number 2.1. ]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
\ No newline at end of file
diff --git a/core/make.sh b/core/make.sh
new file mode 100755
index 000000000..78d91b33a
--- /dev/null
+++ b/core/make.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+#javadoc -public -d doc *.java
+#javadoc -private -d doc *.java
+chmod +x preproc.pl
+./preproc.pl
+jikes -d . +D *.java
diff --git a/core/preproc.pl b/core/preproc.pl
new file mode 100755
index 000000000..40ba9bba2
--- /dev/null
+++ b/core/preproc.pl
@@ -0,0 +1,186 @@
+#!/usr/bin/perl -w
+
+$basedir = 'src/processing/core';
+
+@contents = ();
+
+# next slurp methods from PGraphics
+open(F, "$basedir/PGraphics.java") || die $!;
+foreach $line () {
+ push @contents, $line;
+}
+close(F);
+
+# PGraphics subclasses PImage.. now get those methods
+open(F, "$basedir/PImage.java") || die $!;
+foreach $line () {
+ push @contents, $line;
+}
+close(F);
+
+#open(DEBUG, ">debug.java") || die $!;
+#print DEBUG @contents;
+#close(DEBUG);
+#exit;
+
+
+open(APPLET, "$basedir/PApplet.java") || die $!;
+@applet =