diff --git a/.classpath b/.classpath index be02d8d67..b68e5e764 100644 --- a/.classpath +++ b/.classpath @@ -10,7 +10,7 @@ - + @@ -20,6 +20,13 @@ + + + + + + + diff --git a/.gitignore b/.gitignore index 4400c7eb4..3c8c0fe5c 100644 --- a/.gitignore +++ b/.gitignore @@ -21,32 +21,36 @@ build/windows/libastylej* build/windows/arduino-*.zip build/windows/dist/*.tar.gz build/windows/dist/*.tar.bz2 -build/windows/launch4j-* +build/windows/launch4j-*.tgz +build/windows/launch4j-*.zip build/windows/launcher/launch4j build/windows/WinAVR-*.zip build/macosx/arduino-*.zip build/macosx/dist/*.tar.gz build/macosx/dist/*.tar.bz2 +build/macosx/*.tar.bz2 build/macosx/libastylej* build/macosx/appbundler*.jar build/macosx/appbundler*.zip build/macosx/appbundler build/macosx/appbundler-1.0ea-arduino2 +build/macosx/appbundler-1.0ea-upstream1 build/linux/work/ build/linux/dist/*.tar.gz build/linux/dist/*.tar.bz2 build/linux/*.tgz +build/linux/*.tar.xz +build/linux/*.tar.bz2 build/linux/*.zip build/linux/libastylej* build/shared/reference*.zip +build/shared/Edison*.zip +build/shared/Galileo*.zip test-bin *.iml .idea .DS_Store .directory -build/windows/launch4j-* -build/windows/launcher/launch4j -build/windows/WinAVR-*.zip hardware/arduino/avr/libraries/Bridge/examples/XivelyClient/passwords.h avr-toolchain-*.zip /hardware/tools/esp8266/utils/ @@ -57,4 +61,14 @@ avr-toolchain-*.zip /hardware/tools/bossac.exe /hardware/tools/listComPorts.exe +/app/nbproject/private/ +/arduino-core/nbproject/private/ +/app/build/ +/arduino-core/build/ + +manifest.mf +nbbuild.xml +nbproject build/macosx/esptool-*-osx.zip + +build/macosx/dist/osx-xtensa-lx106-elf.tgz diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs index 76460b409..89352b22f 100644 --- a/.settings/org.eclipse.jdt.core.prefs +++ b/.settings/org.eclipse.jdt.core.prefs @@ -1,26 +1,29 @@ -#Sat Dec 31 13:42:35 CET 2011 eclipse.preferences.version=1 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_annotation=0 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 -org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=18 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_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=16 +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=80 -org.eclipse.jdt.core.formatter.alignment_for_enum_constants=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_method_declaration=0 org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=18 org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=18 +org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80 org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16 org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16 org.eclipse.jdt.core.formatter.blank_lines_after_imports=1 org.eclipse.jdt.core.formatter.blank_lines_after_package=1 org.eclipse.jdt.core.formatter.blank_lines_before_field=0 @@ -40,6 +43,7 @@ org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line @@ -56,10 +60,16 @@ org.eclipse.jdt.core.formatter.comment.indent_root_tags=true org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert org.eclipse.jdt.core.formatter.comment.line_length=80 +org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true +org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true +org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false org.eclipse.jdt.core.formatter.compact_else_if=true org.eclipse.jdt.core.formatter.continuation_indentation=2 org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2 +org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off +org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false +org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true org.eclipse.jdt.core.formatter.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 @@ -70,11 +80,18 @@ 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=4 +org.eclipse.jdt.core.formatter.indentation.size=2 +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_member=insert -org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert @@ -122,6 +139,7 @@ org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=inser org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert +org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert org.eclipse.jdt.core.formatter.insert_space_after_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 @@ -140,12 +158,14 @@ org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invoca org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert @@ -169,6 +189,7 @@ org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invoc org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert @@ -196,6 +217,7 @@ org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do n org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert org.eclipse.jdt.core.formatter.insert_space_before_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 @@ -224,6 +246,7 @@ org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invoc org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert @@ -233,6 +256,7 @@ org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=inser org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert @@ -256,5 +280,8 @@ org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1 org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true org.eclipse.jdt.core.formatter.tabulation.char=space org.eclipse.jdt.core.formatter.tabulation.size=2 +org.eclipse.jdt.core.formatter.use_on_off_tags=false org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false -org.eclipse.jdt.core.formatter.wrap_before_binary_operator=false +org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true +org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true +org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true diff --git a/README.md b/README.md index bf6cba3b3..99c9de21b 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,20 @@ Arduino-compatible IDE with ESP8266 support =========================================== +![Linux build status](http://img.shields.io/travis/igrr/Arduino.svg) + This project brings support for ESP8266 chip to the Arduino environment. ESP8266WiFi library bundled with this project has the same interface as the WiFi Shield library, making it easy to re-use existing code and libraries. -### Downloads ### +### Installing with Boards Manager ### -| OS | Build status | Latest release | Alpha Version | -| --- | ------------ | -------------- | --------------- | -| Linux | [![Linux build status](http://img.shields.io/travis/igrr/Arduino.svg)](https://travis-ci.org/igrr/Arduino) | [arduino-1.6.1-linux64.tar.xz](../../releases/download/1.6.1-esp8266-1/arduino-1.6.1-linux64.tar.xz) | | -| Windows | [![Windows build status](http://img.shields.io/appveyor/ci/igrr/Arduino.svg)](https://ci.appveyor.com/project/igrr/Arduino) | [arduino-1.6.1-p1-windows.zip](https://github.com/igrr/Arduino/releases/download/1.6.1-esp8266-1/arduino-1.6.1-p1-windows.zip) | [appveyor 64Bit Build](https://ci.appveyor.com/project/igrr/Arduino/build/artifacts) | -| OS X | | [arduino-1.6.1-macosx-java-latest-signed.zip](../../releases/download/1.6.1-esp8266-1/arduino-1.6.1-macosx-java-latest-signed.zip) | | +Starting with 1.6.4, Arduino allows installation of third-party platform packages using Boards Manager. We have packages available for Windows, Mac OS, and Linux (32 and 64 bit). +- Install Arduino 1.6.4 from the [Arduino website](http://www.arduino.cc/en/main/software). +- Start Arduino and open Perferences window. +- Enter ```http://arduino.esp8266.com/package_esp8266com_index.json``` into *Additional Board Manager URLs* field. You can add multiple URLs, separating them with commas. +- Open Boards Manager from Tools > Board menu and install *esp8266* platform (and don't forget to select your ESP8266 board from Tools > Board menu after installation). -### Building from source ### +### Building latest version from source ### ``` $ git clone https://github.com/esp8266/Arduino.git $ cd Arduino/build @@ -20,8 +22,9 @@ $ ant dist ``` ### Supported boards ### -- [Wifio](http://wifio.cc) - Generic esp8266 modules (without auto-reset support) +- NodeMCU +- Olimex MOD-WIFI-ESP8266 ### Things that work ### diff --git a/app/.classpath b/app/.classpath index aca931155..356c15869 100644 --- a/app/.classpath +++ b/app/.classpath @@ -7,10 +7,17 @@ + + + + + + + @@ -21,5 +28,9 @@ + + + + diff --git a/app/.editorconfig b/app/.editorconfig new file mode 100644 index 000000000..bd8c8987e --- /dev/null +++ b/app/.editorconfig @@ -0,0 +1,16 @@ +# EditorConfig is awesome: http://EditorConfig.org + +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +[*] +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 2 +charset = utf-8 + +[*.{md,adoc}] +indent_style = space +trim_trailing_whitespace = false diff --git a/app/.settings/org.eclipse.jdt.core.prefs b/app/.settings/org.eclipse.jdt.core.prefs index 109d1ff5d..4b64040da 100644 --- a/app/.settings/org.eclipse.jdt.core.prefs +++ b/app/.settings/org.eclipse.jdt.core.prefs @@ -1,4 +1,3 @@ -#Wed Jan 11 13:49:57 CET 2012 eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 @@ -66,6 +65,7 @@ org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning org.eclipse.jdt.core.compiler.source=1.6 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_annotation=0 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=18 @@ -76,18 +76,21 @@ 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_method_declaration=0 org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=18 org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=18 +org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80 org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16 org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16 org.eclipse.jdt.core.formatter.blank_lines_after_imports=1 org.eclipse.jdt.core.formatter.blank_lines_after_package=1 -org.eclipse.jdt.core.formatter.blank_lines_before_field=1 +org.eclipse.jdt.core.formatter.blank_lines_before_field=0 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 @@ -104,6 +107,7 @@ org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line @@ -120,10 +124,16 @@ org.eclipse.jdt.core.formatter.comment.indent_root_tags=true org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert org.eclipse.jdt.core.formatter.comment.line_length=80 +org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true +org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true +org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false org.eclipse.jdt.core.formatter.compact_else_if=true org.eclipse.jdt.core.formatter.continuation_indentation=2 org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2 +org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off +org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false +org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true org.eclipse.jdt.core.formatter.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 @@ -136,7 +146,15 @@ org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false org.eclipse.jdt.core.formatter.indentation.size=2 org.eclipse.jdt.core.formatter.insert_new_line_after_annotation=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert @@ -184,6 +202,7 @@ org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=inser org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert +org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert org.eclipse.jdt.core.formatter.insert_space_after_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 @@ -202,12 +221,14 @@ org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invoca org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert @@ -231,6 +252,7 @@ org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invoc org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert @@ -258,6 +280,7 @@ org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do n org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert org.eclipse.jdt.core.formatter.insert_space_before_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 @@ -286,6 +309,7 @@ org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invoc org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert @@ -295,6 +319,7 @@ org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=inser org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert @@ -304,6 +329,8 @@ org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_ org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.join_lines_in_comments=true +org.eclipse.jdt.core.formatter.join_wrapped_lines=true org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false @@ -316,5 +343,8 @@ org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1 org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true org.eclipse.jdt.core.formatter.tabulation.char=space org.eclipse.jdt.core.formatter.tabulation.size=2 +org.eclipse.jdt.core.formatter.use_on_off_tags=false org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true +org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true +org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true diff --git a/app/.settings/org.eclipse.jdt.ui.prefs b/app/.settings/org.eclipse.jdt.ui.prefs index 4ce979da4..9ae81ad46 100644 --- a/app/.settings/org.eclipse.jdt.ui.prefs +++ b/app/.settings/org.eclipse.jdt.ui.prefs @@ -1,4 +1,3 @@ -#Tue Jun 03 17:00:03 EDT 2008 eclipse.preferences.version=1 -formatter_profile=_two spaces no tabs -formatter_settings_version=11 +formatter_profile=_Arduino +formatter_settings_version=12 diff --git a/app/build.xml b/app/build.xml index cbab13552..4c20976b6 100644 --- a/app/build.xml +++ b/app/build.xml @@ -48,7 +48,7 @@ - + @@ -99,11 +99,14 @@ + + + diff --git a/app/format/src/AutoFormat.java b/app/format/src/AutoFormat.java index 4e8d8abbd..59640cde8 100644 --- a/app/format/src/AutoFormat.java +++ b/app/format/src/AutoFormat.java @@ -45,7 +45,7 @@ import java.io.*; public void show() { String originalText = editor.textarea.getText(); - int indentSize = Preferences.getInteger("editor.tabs.size"); + int indentSize = PreferencesData.getInteger("editor.tabs.size"); // diff --git a/app/lib/apple.jar b/app/lib/apple.jar index d1aa7851d..6659a81c6 100644 Binary files a/app/lib/apple.jar and b/app/lib/apple.jar differ diff --git a/app/lib/bcpg-jdk15on-152.jar b/app/lib/bcpg-jdk15on-152.jar new file mode 100644 index 000000000..4f5c63105 Binary files /dev/null and b/app/lib/bcpg-jdk15on-152.jar differ diff --git a/app/lib/bcprov-jdk15on-152.jar b/app/lib/bcprov-jdk15on-152.jar new file mode 100644 index 000000000..6c54dd901 Binary files /dev/null and b/app/lib/bcprov-jdk15on-152.jar differ diff --git a/app/lib/commons-compress-1.8.jar b/app/lib/commons-compress-1.8.jar new file mode 100644 index 000000000..940b06873 Binary files /dev/null and b/app/lib/commons-compress-1.8.jar differ diff --git a/app/lib/commons-compress.LICENSE.ASL-2.0.txt b/app/lib/commons-compress.LICENSE.ASL-2.0.txt new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/app/lib/commons-compress.LICENSE.ASL-2.0.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/app/lib/commons-lang3-3.3.2.jar b/app/lib/commons-lang3-3.3.2.jar new file mode 100644 index 000000000..2ce08ae99 Binary files /dev/null and b/app/lib/commons-lang3-3.3.2.jar differ diff --git a/app/lib/commons-lang3.LICENSE.ASL-2.0.txt b/app/lib/commons-lang3.LICENSE.ASL-2.0.txt new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/app/lib/commons-lang3.LICENSE.ASL-2.0.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/app/lib/guava-18.0.LICENSE.ASL-2.0.txt b/app/lib/guava-18.0.LICENSE.ASL-2.0.txt new file mode 100644 index 000000000..6b0b1270f --- /dev/null +++ b/app/lib/guava-18.0.LICENSE.ASL-2.0.txt @@ -0,0 +1,203 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/app/lib/guava-18.0.jar b/app/lib/guava-18.0.jar new file mode 100644 index 000000000..8f89e4901 Binary files /dev/null and b/app/lib/guava-18.0.jar differ diff --git a/app/lib/jackson-annotations-2.2.3.jar b/app/lib/jackson-annotations-2.2.3.jar new file mode 100644 index 000000000..b62c87d7e Binary files /dev/null and b/app/lib/jackson-annotations-2.2.3.jar differ diff --git a/app/lib/jackson-core-2.2.3.jar b/app/lib/jackson-core-2.2.3.jar new file mode 100644 index 000000000..24318a464 Binary files /dev/null and b/app/lib/jackson-core-2.2.3.jar differ diff --git a/app/lib/jackson-databind-2.2.3.jar b/app/lib/jackson-databind-2.2.3.jar new file mode 100644 index 000000000..854508478 Binary files /dev/null and b/app/lib/jackson-databind-2.2.3.jar differ diff --git a/app/lib/jackson-module-mrbean-2.2.3.jar b/app/lib/jackson-module-mrbean-2.2.3.jar new file mode 100644 index 000000000..a4a3b738e Binary files /dev/null and b/app/lib/jackson-module-mrbean-2.2.3.jar differ diff --git a/app/lib/java-semver-0.8.0.jar b/app/lib/java-semver-0.8.0.jar new file mode 100644 index 000000000..967f0d154 Binary files /dev/null and b/app/lib/java-semver-0.8.0.jar differ diff --git a/app/lib/java-semver.LICENSE.MIT.txt b/app/lib/java-semver.LICENSE.MIT.txt new file mode 100644 index 000000000..e69de29bb diff --git a/app/lib/rsyntaxtextarea-2.5.6.1+arduino.jar b/app/lib/rsyntaxtextarea-2.5.6.1+arduino.jar new file mode 100644 index 000000000..c1dbc6090 Binary files /dev/null and b/app/lib/rsyntaxtextarea-2.5.6.1+arduino.jar differ diff --git a/app/lib/rsyntaxtextarea-BSD.txt b/app/lib/rsyntaxtextarea-BSD.txt new file mode 100644 index 000000000..3a6e63890 --- /dev/null +++ b/app/lib/rsyntaxtextarea-BSD.txt @@ -0,0 +1,24 @@ +Copyright (c) 2012, Robert Futrell +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 author 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 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/app/src/cc/arduino/contributions/BuiltInCoreIsNewerCheck.java b/app/src/cc/arduino/contributions/BuiltInCoreIsNewerCheck.java new file mode 100644 index 000000000..2e997c9ac --- /dev/null +++ b/app/src/cc/arduino/contributions/BuiltInCoreIsNewerCheck.java @@ -0,0 +1,115 @@ +/* + * This file is part of Arduino. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ + +package cc.arduino.contributions; + +import cc.arduino.contributions.filters.BuiltInPredicate; +import cc.arduino.contributions.filters.InstalledPredicate; +import cc.arduino.contributions.packages.ContributedPackage; +import cc.arduino.contributions.packages.ContributedPlatform; +import cc.arduino.view.Event; +import com.google.common.base.Function; +import com.google.common.base.Predicates; +import com.google.common.collect.Collections2; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; +import processing.app.Base; +import processing.app.BaseNoGui; +import processing.app.I18n; +import processing.app.PreferencesData; + +import javax.swing.*; +import java.awt.event.ActionEvent; +import java.util.LinkedList; +import java.util.List; + +import static processing.app.I18n._; + +public class BuiltInCoreIsNewerCheck implements Runnable { + + private final Base base; + + public BuiltInCoreIsNewerCheck(Base base) { + this.base = base; + } + + @Override + public void run() { + try { + builtInPackageIsNewerCheck(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + private void builtInPackageIsNewerCheck() throws InterruptedException { + if (PreferencesData.getInteger("builtin_platform_is_newer", -1) >= BaseNoGui.REVISION) { + return; + } + + LinkedList contributedPlatforms = Lists.newLinkedList(Iterables.concat(Collections2.transform(BaseNoGui.indexer.getPackages(), new Function>() { + @Override + public List apply(ContributedPackage input) { + return input.getPlatforms(); + } + }))); + + List installedBuiltInPlatforms = new LinkedList(Collections2.filter(contributedPlatforms, Predicates.and(new InstalledPredicate(), new BuiltInPredicate()))); + if (installedBuiltInPlatforms.size() != 1) { + return; + } + final ContributedPlatform installedBuiltIn = installedBuiltInPlatforms.get(0); + + ContributedPlatform installedNotBuiltIn = BaseNoGui.indexer.getInstalled(installedBuiltIn.getParentPackage().getName(), installedBuiltIn.getArchitecture()); + if (installedNotBuiltIn == null) { + return; + } + + while (!base.hasActiveEditor()) { + Thread.sleep(100); + } + + if (VersionHelper.valueOf(installedBuiltIn.getParsedVersion()).greaterThan(VersionHelper.valueOf(installedNotBuiltIn.getParsedVersion()))) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + PreferencesData.setInteger("builtin_platform_is_newer", BaseNoGui.REVISION); + assert base.hasActiveEditor(); + int chosenOption = JOptionPane.showConfirmDialog(base.getActiveEditor(), I18n.format(_("The IDE includes an updated {0} package, but you're using an older one.\nDo you want to upgrade {0}?"), installedBuiltIn.getName()), I18n.format(_("A newer {0} package is available"), installedBuiltIn.getName()), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); + if (chosenOption == JOptionPane.YES_OPTION) { + Action openBoardsManager = base.getOpenBoardsManager(); + Event event = new Event(base.getActiveEditor(), ActionEvent.ACTION_PERFORMED, installedBuiltIn.getName()); + event.getPayload().put("filterText", installedBuiltIn.getName()); + openBoardsManager.actionPerformed(event); + } + } + }); + } + } +} diff --git a/app/src/cc/arduino/contributions/filters/NoopPredicate.java b/app/src/cc/arduino/contributions/filters/NoopPredicate.java new file mode 100644 index 000000000..f0a511af4 --- /dev/null +++ b/app/src/cc/arduino/contributions/filters/NoopPredicate.java @@ -0,0 +1,47 @@ +/* + * This file is part of Arduino. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ + +package cc.arduino.contributions.filters; + +import com.google.common.base.Predicate; + +public class NoopPredicate implements Predicate { + + @Override + public boolean apply(T input) { + return true; + } + + @Override + public boolean equals(Object obj) { + return obj instanceof NoopPredicate; + } + + +} diff --git a/app/src/cc/arduino/contributions/libraries/filters/CategoryPredicate.java b/app/src/cc/arduino/contributions/libraries/filters/CategoryPredicate.java new file mode 100644 index 000000000..7c26606af --- /dev/null +++ b/app/src/cc/arduino/contributions/libraries/filters/CategoryPredicate.java @@ -0,0 +1,53 @@ +/* + * This file is part of Arduino. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ + +package cc.arduino.contributions.libraries.filters; + +import cc.arduino.contributions.libraries.ContributedLibrary; +import com.google.common.base.Predicate; + +public class CategoryPredicate implements Predicate { + + private final String category; + + public CategoryPredicate(String category) { + this.category = category; + } + + @Override + public boolean apply(ContributedLibrary input) { + return input.getCategory() != null && category.equals(input.getCategory()); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof CategoryPredicate && ((CategoryPredicate) obj).category.equals(category); + } + +} diff --git a/app/src/cc/arduino/contributions/libraries/filters/InstalledLibraryPredicate.java b/app/src/cc/arduino/contributions/libraries/filters/InstalledLibraryPredicate.java new file mode 100644 index 000000000..70132389c --- /dev/null +++ b/app/src/cc/arduino/contributions/libraries/filters/InstalledLibraryPredicate.java @@ -0,0 +1,64 @@ +/* + * This file is part of Arduino. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ + +package cc.arduino.contributions.libraries.filters; + +import cc.arduino.contributions.filters.InstalledPredicate; +import cc.arduino.contributions.libraries.ContributedLibrary; +import cc.arduino.contributions.libraries.LibrariesIndex; +import com.google.common.base.Predicate; +import com.google.common.collect.Collections2; + +import java.util.Collection; + +public class InstalledLibraryPredicate implements Predicate { + + private final LibrariesIndex index; + + public InstalledLibraryPredicate(LibrariesIndex index) { + this.index = index; + } + + @Override + public boolean apply(ContributedLibrary input) { + if (input.isInstalled()) { + return true; + } + + Collection installed = Collections2.filter(index.find(input.getName()), new InstalledPredicate()); + + return !installed.isEmpty(); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof InstalledLibraryPredicate; + } + +} diff --git a/app/src/cc/arduino/contributions/libraries/filters/OnlyUpstreamReleasePredicate.java b/app/src/cc/arduino/contributions/libraries/filters/OnlyUpstreamReleasePredicate.java new file mode 100644 index 000000000..359cbd623 --- /dev/null +++ b/app/src/cc/arduino/contributions/libraries/filters/OnlyUpstreamReleasePredicate.java @@ -0,0 +1,47 @@ +/* + * This file is part of Arduino. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ + +package cc.arduino.contributions.libraries.filters; + +import cc.arduino.contributions.libraries.ContributedLibrary; +import com.google.common.base.Predicate; +import processing.app.packages.UserLibrary; + +public class OnlyUpstreamReleasePredicate implements Predicate { + + @Override + public boolean apply(ContributedLibrary input) { + return !(input instanceof UserLibrary); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof OnlyUpstreamReleasePredicate; + } +} diff --git a/app/src/cc/arduino/contributions/libraries/filters/TypePredicate.java b/app/src/cc/arduino/contributions/libraries/filters/TypePredicate.java new file mode 100644 index 000000000..4999d9252 --- /dev/null +++ b/app/src/cc/arduino/contributions/libraries/filters/TypePredicate.java @@ -0,0 +1,53 @@ +/* + * This file is part of Arduino. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ + +package cc.arduino.contributions.libraries.filters; + +import cc.arduino.contributions.libraries.ContributedLibrary; +import com.google.common.base.Predicate; + +public class TypePredicate implements Predicate { + + private final String type; + + public TypePredicate(String type) { + this.type = type; + } + + @Override + public boolean apply(ContributedLibrary input) { + return input.getTypes() != null && input.getTypes().contains(type); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof TypePredicate && ((TypePredicate) obj).type.equals(type); + } + +} diff --git a/app/src/cc/arduino/contributions/libraries/ui/ContributedLibraryTableCell.java b/app/src/cc/arduino/contributions/libraries/ui/ContributedLibraryTableCell.java new file mode 100644 index 000000000..2ea96303c --- /dev/null +++ b/app/src/cc/arduino/contributions/libraries/ui/ContributedLibraryTableCell.java @@ -0,0 +1,441 @@ +/* + * This file is part of Arduino. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ +package cc.arduino.contributions.libraries.ui; + +import cc.arduino.contributions.VersionComparator; +import cc.arduino.contributions.filters.BuiltInPredicate; +import cc.arduino.contributions.filters.InstalledPredicate; +import cc.arduino.contributions.libraries.ContributedLibrary; +import cc.arduino.contributions.libraries.filters.OnlyUpstreamReleasePredicate; +import cc.arduino.contributions.packages.DownloadableContribution; +import cc.arduino.contributions.DownloadableContributionVersionComparator; +import cc.arduino.contributions.ui.InstallerTableCell; +import cc.arduino.contributions.ui.listeners.DelegatingKeyListener; +import cc.arduino.utils.ReverseComparator; +import com.google.common.base.Function; +import com.google.common.base.Predicates; +import com.google.common.collect.Collections2; +import com.google.common.collect.Lists; +import processing.app.Base; + +import javax.swing.*; +import javax.swing.border.EmptyBorder; +import javax.swing.event.HyperlinkEvent; +import javax.swing.event.HyperlinkListener; +import javax.swing.text.Document; +import javax.swing.text.html.HTMLDocument; +import javax.swing.text.html.StyleSheet; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +import static processing.app.I18n._; +import static processing.app.I18n.format; + +@SuppressWarnings("serial") +public class ContributedLibraryTableCell extends InstallerTableCell { + + private JPanel panel; + private JButton installButton; + private Component installButtonPlaceholder; + private JComboBox downgradeChooser; + private JComboBox versionToInstallChooser; + private JButton downgradeButton; + private JPanel buttonsPanel; + private JPanel inactiveButtonsPanel; + private JLabel statusLabel; + + public ContributedLibraryTableCell() { + { + installButton = new JButton(_("Install")); + installButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + onInstall(editorValue.getSelected(), editorValue.getInstalled()); + } + }); + int width = installButton.getPreferredSize().width; + installButtonPlaceholder = Box.createRigidArea(new Dimension(width, 1)); + } + + downgradeButton = new JButton(_("Install")); + downgradeButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + ContributedLibrary selected = (ContributedLibrary) downgradeChooser.getSelectedItem(); + onInstall(selected, editorValue.getInstalled()); + } + }); + + downgradeChooser = new JComboBox(); + downgradeChooser.addItem("-"); + downgradeChooser.setMaximumSize(downgradeChooser.getPreferredSize()); + downgradeChooser.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + Object selectVersionItem = downgradeChooser.getItemAt(0); + boolean disableDowngrade = (e.getItem() == selectVersionItem); + downgradeButton.setEnabled(!disableDowngrade); + } + }); + + versionToInstallChooser = new JComboBox(); + versionToInstallChooser.addItem("-"); + versionToInstallChooser.setMaximumSize(versionToInstallChooser.getPreferredSize()); + versionToInstallChooser.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + editorValue.select((ContributedLibrary) versionToInstallChooser.getSelectedItem()); + } + }); + + panel = new JPanel(); + panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); + + makeNewDescription(panel); + + { + buttonsPanel = new JPanel(); + buttonsPanel.setLayout(new BoxLayout(buttonsPanel, BoxLayout.X_AXIS)); + buttonsPanel.setOpaque(false); + + buttonsPanel.add(Box.createHorizontalStrut(7)); + buttonsPanel.add(downgradeChooser); + buttonsPanel.add(Box.createHorizontalStrut(5)); + buttonsPanel.add(downgradeButton); + + buttonsPanel.add(Box.createHorizontalGlue()); + + buttonsPanel.add(versionToInstallChooser); + buttonsPanel.add(Box.createHorizontalStrut(5)); + buttonsPanel.add(installButton); + buttonsPanel.add(Box.createHorizontalStrut(5)); + buttonsPanel.add(Box.createHorizontalStrut(15)); + + panel.add(buttonsPanel); + } + + { + inactiveButtonsPanel = new JPanel(); + inactiveButtonsPanel.setLayout(new BoxLayout(inactiveButtonsPanel, BoxLayout.X_AXIS)); + inactiveButtonsPanel.setOpaque(false); + + int height = installButton.getMinimumSize().height; + inactiveButtonsPanel.add(Box.createVerticalStrut(height)); + inactiveButtonsPanel.add(Box.createGlue()); + + statusLabel = new JLabel(" "); + inactiveButtonsPanel.add(statusLabel); + inactiveButtonsPanel.add(Box.createHorizontalStrut(15)); + + panel.add(inactiveButtonsPanel); + } + + panel.add(Box.createVerticalStrut(15)); + } + + private JTextPane makeNewDescription(JPanel panel) { + if (panel.getComponentCount() > 0) { + panel.remove(0); + } + JTextPane description = new JTextPane(); + description.setInheritsPopupMenu(true); + Insets margin = description.getMargin(); + margin.bottom = 0; + description.setMargin(margin); + description.setContentType("text/html"); + Document doc = description.getDocument(); + if (doc instanceof HTMLDocument) { + HTMLDocument html = (HTMLDocument) doc; + StyleSheet stylesheet = html.getStyleSheet(); + stylesheet.addRule("body { margin: 0; padding: 0;" + + "font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;" + + "font-size: 100%;" + "font-size: 0.95em; }"); + } + description.setOpaque(false); + description.setBorder(new EmptyBorder(4, 7, 7, 7)); + description.setHighlighter(null); + description.setEditable(false); + description.addHyperlinkListener(new HyperlinkListener() { + @Override + public void hyperlinkUpdate(HyperlinkEvent e) { + if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { + Base.openURL(e.getDescription()); + } + } + }); + description.addKeyListener(new DelegatingKeyListener(parentTable)); + panel.add(description, 0); + return description; + } + + protected void onRemove(ContributedLibrary selected) { + // Empty + } + + protected void onInstall(ContributedLibrary selected, ContributedLibrary installed) { + // Empty + } + + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, + boolean hasFocus, int row, + int column) { + parentTable = table; + setEnabled(false); + Component component = getUpdatedCellComponent(value, isSelected, row, false); + if (row % 2 == 0) { + component.setBackground(new Color(236, 241, 241)); //#ecf1f1 + } else { + component.setBackground(new Color(255, 255, 255)); + } + + int height = new Double(component.getPreferredSize().getHeight()).intValue(); + if (table.getRowHeight(row) < height) { + table.setRowHeight(row, height); + } + + return component; + } + + private LibrariesIndexTableModel.ContributedLibraryReleases editorValue; + private JTable parentTable; + + @Override + public Object getCellEditorValue() { + return editorValue; + } + + @Override + public Component getTableCellEditorComponent(JTable table, Object value, + boolean isSelected, int row, + int column) { + parentTable = table; + editorValue = (LibrariesIndexTableModel.ContributedLibraryReleases) value; + setEnabled(true); + + final ContributedLibrary installed = editorValue.getInstalled(); + + List releases = new LinkedList(Collections2.filter(editorValue.releases, new OnlyUpstreamReleasePredicate())); + List uninstalledReleases = new LinkedList(Collections2.filter(releases, Predicates.not(new InstalledPredicate()))); + + List installedBuiltIn = new LinkedList(Collections2.filter(releases, Predicates.and(new InstalledPredicate(), new BuiltInPredicate()))); + + if (installed != null && !installedBuiltIn.contains(installed)) { + uninstalledReleases.addAll(installedBuiltIn); + } + + Collections.sort(uninstalledReleases, new ReverseComparator(new DownloadableContributionVersionComparator())); + + downgradeChooser.removeAllItems(); + downgradeChooser.addItem(_("Select version")); + + final List uninstalledPreviousReleases = Lists.newLinkedList(); + final List uninstalledNewerReleases = Lists.newLinkedList(); + + final VersionComparator versionComparator = new VersionComparator(); + Lists.newLinkedList(Lists.transform(uninstalledReleases, new Function() { + @Override + public ContributedLibrary apply(ContributedLibrary input) { + if (installed == null || versionComparator.greaterThan(installed.getParsedVersion(), input.getParsedVersion())) { + uninstalledPreviousReleases.add(input); + } else { + uninstalledNewerReleases.add(input); + } + + return input; + } + })); + for (ContributedLibrary release : uninstalledNewerReleases) { + downgradeChooser.addItem(release); + } + for (ContributedLibrary release : uninstalledPreviousReleases) { + downgradeChooser.addItem(release); + } + + downgradeChooser.setVisible(installed != null && (!uninstalledPreviousReleases.isEmpty() || uninstalledNewerReleases.size() > 1)); + downgradeButton.setVisible(installed != null && (!uninstalledPreviousReleases.isEmpty() || uninstalledNewerReleases.size() > 1)); + + versionToInstallChooser.removeAllItems(); + for (ContributedLibrary release : uninstalledReleases) { + versionToInstallChooser.addItem(release); + } + versionToInstallChooser.setVisible(installed == null && uninstalledReleases.size() > 1); + + Component component = getUpdatedCellComponent(value, true, row, !installedBuiltIn.isEmpty()); + component.setBackground(new Color(218, 227, 227)); //#dae3e3 + return component; + } + + private Component getUpdatedCellComponent(Object value, boolean isSelected, int row, boolean hasBuiltInRelease) { + LibrariesIndexTableModel.ContributedLibraryReleases releases = (LibrariesIndexTableModel.ContributedLibraryReleases) value; + + JTextPane description = makeNewDescription(panel); + + //FIXME: happens on macosx, don't know why + if (releases == null) { + return panel; + } + + ContributedLibrary selected = releases.getSelected(); + ContributedLibrary installed = releases.getInstalled(); + + boolean removable, installable, upgradable; + if (installed == null) { + installable = true; + removable = false; + upgradable = false; + } else { + installable = false; + removable = !installed.isReadOnly() && !hasBuiltInRelease; + upgradable = new DownloadableContributionVersionComparator().compare(selected, installed) > 0; + } + if (installable) { + installButton.setText(_("Install")); + } + if (upgradable) { + installButton.setText(_("Update")); + } + installButton.setVisible(installable || upgradable); + installButtonPlaceholder.setVisible(!(installable || upgradable)); + + String name = selected.getName(); + String author = selected.getAuthor(); + // String maintainer = selectedLib.getMaintainer(); + String website = selected.getWebsite(); + String sentence = selected.getSentence(); + String paragraph = selected.getParagraph(); + // String availableVer = selectedLib.getVersion(); + // String url = selected.getUrl(); + + String midcolor = isSelected ? "#000000" : "#888888"; + + String desc = ""; + + // Library name... + desc += format("{0}", name); + if (installed != null && installed.isReadOnly()) { + desc += " Built-In "; + } + + // ...author... + desc += format("", midcolor); + if (author != null && !author.isEmpty()) { + desc += format(" by {0}", author); + } + + // ...version. + if (installed != null) { + String installedVer = installed.getParsedVersion(); + if (installedVer == null) { + desc += " " + _("Version unknown"); + } else { + desc += " " + format(_("Version {0}"), installedVer); + } + } + desc += ""; + + if (installed != null) { + desc += " INSTALLED"; + } + + desc += "
"; + + // Description + if (sentence != null) { + desc += format("{0} ", sentence); + if (paragraph != null && !paragraph.isEmpty()) + desc += format("{0}", paragraph); + desc += "
"; + } + if (author != null && !author.isEmpty()) { + desc += format("More info", website); + } + + desc += ""; + description.setText(desc); + description.setBackground(Color.WHITE); + + // for modelToView to work, the text area has to be sized. It doesn't + // matter if it's visible or not. + + // See: + // http://stackoverflow.com/questions/3081210/how-to-set-jtextarea-to-have-height-that-matches-the-size-of-a-text-it-contains + int width = parentTable.getBounds().width; + setJTextPaneDimensionToFitContainedText(description, width); + + if (isSelected) { + panel.setBackground(parentTable.getSelectionBackground()); + panel.setForeground(parentTable.getSelectionForeground()); + } else { + panel.setBackground(parentTable.getBackground()); + panel.setForeground(parentTable.getForeground()); + } + + return panel; + } + + private Timer enabler = new Timer(100, new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + enable(true); + enabler.stop(); + } + }); + + @Override + public void setEnabled(boolean enabled) { + enable(false); + if (enabled) { + enabler.start(); + } else { + enabler.stop(); + } + buttonsPanel.setVisible(enabled); + inactiveButtonsPanel.setVisible(!enabled); + } + + public void enable(boolean enabled) { + installButton.setEnabled(enabled); + } + + public void setStatus(String status) { + statusLabel.setText(status); + } + + public void invalidate() { + panel.invalidate(); + } + +} diff --git a/app/src/cc/arduino/contributions/libraries/ui/DropdownInstalledLibraryItem.java b/app/src/cc/arduino/contributions/libraries/ui/DropdownInstalledLibraryItem.java new file mode 100644 index 000000000..4f48cc395 --- /dev/null +++ b/app/src/cc/arduino/contributions/libraries/ui/DropdownInstalledLibraryItem.java @@ -0,0 +1,62 @@ +/* + * This file is part of Arduino. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ + +package cc.arduino.contributions.libraries.ui; + +import cc.arduino.contributions.libraries.ContributedLibrary; +import cc.arduino.contributions.libraries.LibrariesIndex; +import cc.arduino.contributions.libraries.filters.InstalledLibraryPredicate; +import cc.arduino.contributions.ui.DropdownItem; +import com.google.common.base.Predicate; + +import static processing.app.I18n._; + +public class DropdownInstalledLibraryItem implements DropdownItem { + + private final LibrariesIndex index; + + public DropdownInstalledLibraryItem(LibrariesIndex index) { + this.index = index; + } + + public String toString() { + return _("Installed"); + } + + @Override + public Predicate getFilterPredicate() { + return new InstalledLibraryPredicate(index); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof DropdownInstalledLibraryItem; + } + +} diff --git a/app/src/cc/arduino/contributions/libraries/ui/DropdownLibraryOfCategoryItem.java b/app/src/cc/arduino/contributions/libraries/ui/DropdownLibraryOfCategoryItem.java new file mode 100644 index 000000000..809865ba4 --- /dev/null +++ b/app/src/cc/arduino/contributions/libraries/ui/DropdownLibraryOfCategoryItem.java @@ -0,0 +1,59 @@ +/* + * This file is part of Arduino. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ + +package cc.arduino.contributions.libraries.ui; + +import cc.arduino.contributions.libraries.ContributedLibrary; +import cc.arduino.contributions.libraries.filters.CategoryPredicate; +import cc.arduino.contributions.ui.DropdownItem; +import com.google.common.base.Predicate; + +public class DropdownLibraryOfCategoryItem implements DropdownItem { + + private final String category; + + public DropdownLibraryOfCategoryItem(String category) { + this.category = category; + } + + public String toString() { + return category; + } + + @Override + public Predicate getFilterPredicate() { + return new CategoryPredicate(category); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof DropdownLibraryOfCategoryItem && ((DropdownLibraryOfCategoryItem) obj).category.equals(category); + } + +} diff --git a/app/src/cc/arduino/contributions/libraries/ui/DropdownLibraryOfTypeItem.java b/app/src/cc/arduino/contributions/libraries/ui/DropdownLibraryOfTypeItem.java new file mode 100644 index 000000000..02c9013be --- /dev/null +++ b/app/src/cc/arduino/contributions/libraries/ui/DropdownLibraryOfTypeItem.java @@ -0,0 +1,60 @@ +/* + * This file is part of Arduino. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ + +package cc.arduino.contributions.libraries.ui; + +import cc.arduino.contributions.libraries.ContributedLibrary; +import cc.arduino.contributions.libraries.filters.CategoryPredicate; +import cc.arduino.contributions.libraries.filters.TypePredicate; +import cc.arduino.contributions.ui.DropdownItem; +import com.google.common.base.Predicate; + +public class DropdownLibraryOfTypeItem implements DropdownItem { + + private final String type; + + public DropdownLibraryOfTypeItem(String type) { + this.type = type; + } + + public String toString() { + return type; + } + + @Override + public Predicate getFilterPredicate() { + return new TypePredicate(type); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof DropdownLibraryOfTypeItem && ((DropdownLibraryOfTypeItem) obj).type.equals(type); + } + +} diff --git a/app/src/cc/arduino/contributions/libraries/ui/LibrariesIndexTableModel.java b/app/src/cc/arduino/contributions/libraries/ui/LibrariesIndexTableModel.java new file mode 100644 index 000000000..d5b50f66f --- /dev/null +++ b/app/src/cc/arduino/contributions/libraries/ui/LibrariesIndexTableModel.java @@ -0,0 +1,280 @@ +/* + * This file is part of Arduino. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ +package cc.arduino.contributions.libraries.ui; + +import cc.arduino.contributions.DownloadableContributionBuiltInAtTheBottomComparator; +import cc.arduino.contributions.VersionHelper; +import cc.arduino.contributions.filters.InstalledPredicate; +import cc.arduino.contributions.libraries.ContributedLibrary; +import cc.arduino.contributions.libraries.LibrariesIndexer; +import cc.arduino.contributions.packages.ContributedPlatform; +import cc.arduino.contributions.ui.FilteredAbstractTableModel; +import com.github.zafarkhaja.semver.Version; +import com.google.common.base.Predicate; +import com.google.common.base.Predicates; +import com.google.common.collect.Collections2; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +@SuppressWarnings("serial") +public class LibrariesIndexTableModel extends FilteredAbstractTableModel { + + public final static int DESCRIPTION_COL = 0; + + public static class ContributedLibraryReleases implements Comparable { + + public final String name; + public final List releases; + public final List versions; + + public ContributedLibrary selected; + + public ContributedLibraryReleases(ContributedLibrary library) { + this.name = library.getName(); + this.versions = new LinkedList(); + this.releases = new LinkedList(); + this.selected = null; + add(library); + } + + public boolean shouldContain(ContributedLibrary lib) { + return lib.getName().equals(name); + } + + public void add(ContributedLibrary library) { + releases.add(library); + String version = library.getParsedVersion(); + if (version != null) { + versions.add(version); + } + selected = getLatest(); + } + + public ContributedLibrary getInstalled() { + List installedReleases = new LinkedList(Collections2.filter(releases, new InstalledPredicate())); + Collections.sort(installedReleases, new DownloadableContributionBuiltInAtTheBottomComparator()); + + if (installedReleases.isEmpty()) { + return null; + } + + return installedReleases.get(0); + } + + public ContributedLibrary getLatest() { + return getLatestOf(releases); + } + + public ContributedLibrary getSelected() { + return selected; + } + + public void select(ContributedLibrary value) { + for (ContributedLibrary plat : releases) { + if (plat == value) { + selected = plat; + return; + } + } + } + + @Override + public int compareTo(ContributedLibraryReleases o) { + return name.compareToIgnoreCase(o.name); + } + } + + private final List contributions = new ArrayList(); + + private final String[] columnNames = {"Description"}; + + private final Class[] columnTypes = {ContributedPlatform.class}; + + private LibrariesIndexer indexer; + + public void setIndexer(LibrariesIndexer _index) { + indexer = _index; + } + + Predicate selectedCategoryFilter = null; + String selectedFilters[] = null; + + public void updateIndexFilter(String filters[], Predicate... additionalFilters) { + selectedCategoryFilter = Predicates.and(additionalFilters); + selectedFilters = filters; + update(); + } + + /** + * Check if string contains all the substrings in set. The + * compare is case insensitive. + * + * @param string + * @param filters + * @return true if all the strings in set are contained in + * string. + */ + private boolean stringContainsAll(String string, String filters[]) { + if (string == null) { + return false; + } + + if (filters == null) { + return true; + } + + for (String filter : filters) { + if (!string.toLowerCase().contains(filter.toLowerCase())) { + return false; + } + } + + return true; + } + + private void addContribution(ContributedLibrary lib) { + for (ContributedLibraryReleases contribution : contributions) { + if (!contribution.shouldContain(lib)) + continue; + contribution.add(lib); + return; + } + + contributions.add(new ContributedLibraryReleases(lib)); + } + + @Override + public int getColumnCount() { + return columnNames.length; + } + + @Override + public int getRowCount() { + return contributions.size(); + } + + @Override + public String getColumnName(int column) { + return columnNames[column]; + } + + @Override + public Class getColumnClass(int colum) { + return columnTypes[colum]; + } + + @Override + public void setValueAt(Object value, int row, int col) { + if (col == DESCRIPTION_COL) { + fireTableCellUpdated(row, col); + } + } + + @Override + public Object getValueAt(int row, int col) { + if (row >= contributions.size()) { + return null; + } + ContributedLibraryReleases contribution = contributions.get(row); + if (col == DESCRIPTION_COL) { + return contribution;// .getSelected(); + } + return null; + } + + @Override + public boolean isCellEditable(int row, int col) { + return col == DESCRIPTION_COL; + } + + public ContributedLibraryReleases getReleases(int row) { + return contributions.get(row); + } + + public ContributedLibrary getSelectedRelease(int row) { + return contributions.get(row).getSelected(); + } + + public void update() { + updateContributions(); + fireTableDataChanged(); + } + + private void applyFilterToLibrary(ContributedLibrary lib) { + if (selectedCategoryFilter != null && !selectedCategoryFilter.apply(lib)) { + return; + } + if (!stringContainsAll(lib.getName(), selectedFilters) && !stringContainsAll(lib.getParagraph(), selectedFilters) && !stringContainsAll(lib.getSentence(), selectedFilters)) { + return; + } + addContribution(lib); + } + + public void updateLibrary(ContributedLibrary lib) { + // Find the row interested in the change + int row = -1; + for (ContributedLibraryReleases releases : contributions) { + if (releases.shouldContain(lib)) + row = contributions.indexOf(releases); + } + + updateContributions(); + + // If the library is found in the list send update event + // or insert event on the specific row... + for (ContributedLibraryReleases releases : contributions) { + if (releases.shouldContain(lib)) { + if (row == -1) { + row = contributions.indexOf(releases); + fireTableRowsInserted(row, row); + } else { + fireTableRowsUpdated(row, row); + } + return; + } + } + // ...otherwise send a row deleted event + fireTableRowsDeleted(row, row); + } + + private void updateContributions() { + contributions.clear(); + for (ContributedLibrary l : indexer.getIndex().getLibraries()) { + applyFilterToLibrary(l); + } + for (ContributedLibrary l : indexer.getInstalledLibraries()) { + applyFilterToLibrary(l); + } + Collections.sort(contributions); + } + +} diff --git a/app/src/cc/arduino/contributions/libraries/ui/LibraryManagerUI.java b/app/src/cc/arduino/contributions/libraries/ui/LibraryManagerUI.java new file mode 100644 index 000000000..675132019 --- /dev/null +++ b/app/src/cc/arduino/contributions/libraries/ui/LibraryManagerUI.java @@ -0,0 +1,285 @@ +/* + * This file is part of Arduino. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ +package cc.arduino.contributions.libraries.ui; + +import cc.arduino.contributions.libraries.ContributedLibrary; +import cc.arduino.contributions.libraries.LibrariesIndexer; +import cc.arduino.contributions.libraries.LibraryInstaller; +import cc.arduino.contributions.packages.DownloadableContribution; +import cc.arduino.contributions.ui.InstallerJDialogUncaughtExceptionHandler; +import cc.arduino.contributions.ui.*; +import cc.arduino.utils.Progress; +import com.google.common.base.Predicate; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.Collection; + +import static processing.app.I18n._; + +@SuppressWarnings("serial") +public class LibraryManagerUI extends InstallerJDialog { + + private LibrariesIndexer indexer; + private final JComboBox typeChooser; + private Predicate typeFilter; + + @Override + protected FilteredAbstractTableModel createContribModel() { + return new LibrariesIndexTableModel(); + } + + private LibrariesIndexTableModel getContribModel() { + return (LibrariesIndexTableModel) contribModel; + } + + @Override + protected InstallerTableCell createCellRenderer() { + return new ContributedLibraryTableCell(); + } + + @Override + protected InstallerTableCell createCellEditor() { + return new ContributedLibraryTableCell() { + @Override + protected void onInstall(ContributedLibrary selectedLibrary, ContributedLibrary installedLibrary) { + if (selectedLibrary.isReadOnly()) { + onRemovePressed(installedLibrary); + } else { + onInstallPressed(selectedLibrary, installedLibrary); + } + } + + @Override + protected void onRemove(ContributedLibrary library) { + onRemovePressed(library); + } + }; + } + + public LibraryManagerUI(Frame parent) { + super(parent, "Library Manager", Dialog.ModalityType.APPLICATION_MODAL, _("Unable to reach Arduino.cc due to possible network issues.")); + + filtersContainer.add(new JLabel(_("Topic")), 1); + filtersContainer.remove(2); + + typeChooser = new JComboBox(); + typeChooser.setMaximumRowCount(20); + typeChooser.setEnabled(false); + + filtersContainer.add(Box.createHorizontalStrut(5), 0); + filtersContainer.add(new JLabel(_("Type")), 1); + filtersContainer.add(Box.createHorizontalStrut(5), 2); + filtersContainer.add(typeChooser, 3); + } + + protected final ActionListener typeChooserActionListener = new ActionListener() { + + @Override + public void actionPerformed(ActionEvent event) { + DropdownItem selected = (DropdownItem) typeChooser.getSelectedItem(); + if (typeFilter == null || !typeFilter.equals(selected)) { + typeFilter = selected.getFilterPredicate(); + if (contribTable.getCellEditor() != null) { + contribTable.getCellEditor().stopCellEditing(); + } + updateIndexFilter(filters, categoryFilter, typeFilter); + } + } + }; + + @Override + public void updateIndexFilter(String[] filters, Predicate... additionalFilters) { + if (additionalFilters.length == 1) { + additionalFilters = new Predicate[] { additionalFilters[0], typeFilter }; + } + super.updateIndexFilter(filters, additionalFilters); + } + + public void setIndexer(LibrariesIndexer indexer) { + this.indexer = indexer; + + DropdownItem previouslySelectedCategory = (DropdownItem) categoryChooser.getSelectedItem(); + DropdownItem previouslySelectedType = (DropdownItem) typeChooser.getSelectedItem(); + + categoryChooser.removeActionListener(categoryChooserActionListener); + typeChooser.removeActionListener(typeChooserActionListener); + + // TODO: Remove setIndexer and make getContribModel + // return a FilteredAbstractTableModel + getContribModel().setIndexer(indexer); + + categoryFilter = null; + categoryChooser.removeAllItems(); + + // Load categories + categoryChooser.addItem(new DropdownAllItem()); + Collection categories = indexer.getIndex().getCategories(); + for (String category : categories) { + categoryChooser.addItem(new DropdownLibraryOfCategoryItem(category)); + } + + categoryChooser.setEnabled(categoryChooser.getItemCount() > 1); + + categoryChooser.addActionListener(categoryChooserActionListener); + if (previouslySelectedCategory != null) { + categoryChooser.setSelectedItem(previouslySelectedCategory); + } else { + categoryChooser.setSelectedIndex(0); + } + + typeFilter = null; + typeChooser.removeAllItems(); + typeChooser.addItem(new DropdownAllItem()); + typeChooser.addItem(new DropdownInstalledLibraryItem(indexer.getIndex())); + Collection types = indexer.getIndex().getTypes(); + for (String type : types) { + typeChooser.addItem(new DropdownLibraryOfTypeItem(type)); + } + typeChooser.setEnabled(typeChooser.getItemCount() > 1); + typeChooser.addActionListener(typeChooserActionListener); + if (previouslySelectedType != null) { + typeChooser.setSelectedItem(previouslySelectedType); + } else { + typeChooser.setSelectedIndex(0); + } + + filterField.setEnabled(contribModel.getRowCount() > 0); + + // Create LibrariesInstaller tied with the provided index + installer = new LibraryInstaller(indexer) { + @Override + public void onProgress(Progress progress) { + setProgress(progress); + } + }; + } + + public LibrariesIndexer getIndexer() { + return indexer; + } + + public void setProgress(Progress progress) { + progressBar.setValue(progress); + } + + /* + * Installer methods follows + */ + + private LibraryInstaller installer; + private Thread installerThread = null; + + @Override + protected void onCancelPressed() { + super.onUpdatePressed(); + if (installerThread != null) { + installerThread.interrupt(); + } + } + + @Override + protected void onUpdatePressed() { + super.onUpdatePressed(); + installerThread = new Thread(new Runnable() { + @Override + public void run() { + try { + setProgressVisible(true, ""); + installer.updateIndex(); + onIndexesUpdated(); + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + setProgressVisible(false, ""); + } + } + }); + installerThread.setUncaughtExceptionHandler(new InstallerJDialogUncaughtExceptionHandler(this, noConnectionErrorMessage)); + installerThread.start(); + } + + public void onInstallPressed(final ContributedLibrary lib, final ContributedLibrary replaced) { + clearErrorMessage(); + installerThread = new Thread(new Runnable() { + @Override + public void run() { + try { + setProgressVisible(true, _("Installing...")); + installer.install(lib, replaced); + onIndexesUpdated(); // TODO: Do a better job in refreshing only the needed element + //getContribModel().updateLibrary(lib); + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + setProgressVisible(false, ""); + } + } + }); + installerThread.setUncaughtExceptionHandler(new InstallerJDialogUncaughtExceptionHandler(this, noConnectionErrorMessage)); + installerThread.start(); + } + + public void onRemovePressed(final ContributedLibrary lib) { + boolean managedByIndex = indexer.getIndex().getLibraries().contains(lib); + + if (!managedByIndex) { + int chosenOption = JOptionPane.showConfirmDialog(this, _("This library is not listed on Library Manager. You won't be able to resinstall it from here.\nAre you sure you want to delete it?"), _("Please confirm library deletion"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); + if (chosenOption != JOptionPane.YES_OPTION) { + return; + } + } + + clearErrorMessage(); + installerThread = new Thread(new Runnable() { + @Override + public void run() { + try { + setProgressVisible(true, _("Removing...")); + installer.remove(lib); + onIndexesUpdated(); // TODO: Do a better job in refreshing only the needed element + //getContribModel().updateLibrary(lib); + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + setProgressVisible(false, ""); + } + } + }); + installerThread.setUncaughtExceptionHandler(new InstallerJDialogUncaughtExceptionHandler(this, noConnectionErrorMessage)); + installerThread.start(); + } + + protected void onIndexesUpdated() throws Exception { + // Empty + } + +} diff --git a/app/src/cc/arduino/contributions/packages/filters/CategoryPredicate.java b/app/src/cc/arduino/contributions/packages/filters/CategoryPredicate.java new file mode 100644 index 000000000..33cec3e95 --- /dev/null +++ b/app/src/cc/arduino/contributions/packages/filters/CategoryPredicate.java @@ -0,0 +1,53 @@ +/* + * This file is part of Arduino. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ + +package cc.arduino.contributions.packages.filters; + +import cc.arduino.contributions.packages.ContributedPlatform; +import com.google.common.base.Predicate; + +public class CategoryPredicate implements Predicate { + + private final String category; + + public CategoryPredicate(String category) { + this.category = category; + } + + @Override + public boolean apply(ContributedPlatform input) { + return input.getCategory() != null && category.equals(input.getCategory()); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof CategoryPredicate && ((CategoryPredicate) obj).category.equals(category); + } + +} diff --git a/app/src/cc/arduino/contributions/packages/ui/ContributedPlatformTableCell.java b/app/src/cc/arduino/contributions/packages/ui/ContributedPlatformTableCell.java new file mode 100644 index 000000000..b492fa352 --- /dev/null +++ b/app/src/cc/arduino/contributions/packages/ui/ContributedPlatformTableCell.java @@ -0,0 +1,446 @@ +/* + * This file is part of Arduino. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ +package cc.arduino.contributions.packages.ui; + +import cc.arduino.contributions.DownloadableContributionVersionComparator; +import cc.arduino.contributions.VersionComparator; +import cc.arduino.contributions.filters.BuiltInPredicate; +import cc.arduino.contributions.filters.InstalledPredicate; +import cc.arduino.contributions.packages.ContributedBoard; +import cc.arduino.contributions.packages.ContributedHelp; +import cc.arduino.contributions.packages.ContributedPlatform; +import cc.arduino.contributions.packages.DownloadableContribution; +import cc.arduino.contributions.ui.InstallerTableCell; +import cc.arduino.contributions.ui.listeners.DelegatingKeyListener; +import cc.arduino.utils.ReverseComparator; +import com.google.common.base.Function; +import com.google.common.base.Predicates; +import com.google.common.collect.Collections2; +import com.google.common.collect.Lists; +import processing.app.Base; + +import javax.swing.*; +import javax.swing.border.EmptyBorder; +import javax.swing.event.HyperlinkEvent; +import javax.swing.event.HyperlinkListener; +import javax.swing.text.Document; +import javax.swing.text.html.HTMLDocument; +import javax.swing.text.html.StyleSheet; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.util.Collections; +import java.util.LinkedList; + +import static processing.app.I18n._; +import static processing.app.I18n.format; + +@SuppressWarnings("serial") +public class ContributedPlatformTableCell extends InstallerTableCell { + + private JPanel panel; + private JButton installButton; + private JButton removeButton; + private Component removeButtonPlaceholder; + private Component installButtonPlaceholder; + private JComboBox downgradeChooser; + private JComboBox versionToInstallChooser; + private JButton downgradeButton; + private JPanel buttonsPanel; + private JPanel inactiveButtonsPanel; + private JLabel statusLabel; + + public ContributedPlatformTableCell() { + { + installButton = new JButton(_("Install")); + installButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + onInstall(editorValue.getSelected(), editorValue.getInstalled()); + } + }); + int width = installButton.getPreferredSize().width; + installButtonPlaceholder = Box.createRigidArea(new Dimension(width, 1)); + } + + { + removeButton = new JButton(_("Remove")); + removeButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + onRemove(editorValue.getInstalled()); + } + }); + int width = removeButton.getPreferredSize().width; + removeButtonPlaceholder = Box.createRigidArea(new Dimension(width, 1)); + } + + downgradeButton = new JButton(_("Install")); + downgradeButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + ContributedPlatform selected = (ContributedPlatform) downgradeChooser.getSelectedItem(); + onInstall(selected, editorValue.getInstalled()); + } + }); + + downgradeChooser = new JComboBox(); + downgradeChooser.addItem("-"); + downgradeChooser.setMaximumSize(downgradeChooser.getPreferredSize()); + downgradeChooser.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + Object selectVersionItem = downgradeChooser.getItemAt(0); + boolean disableDowngrade = (e.getItem() == selectVersionItem); + downgradeButton.setEnabled(!disableDowngrade); + } + }); + + versionToInstallChooser = new JComboBox(); + versionToInstallChooser.addItem("-"); + versionToInstallChooser.setMaximumSize(versionToInstallChooser.getPreferredSize()); + versionToInstallChooser.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent e) { + editorValue.select((ContributedPlatform) versionToInstallChooser.getSelectedItem()); + } + }); + + panel = new JPanel(); + panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); + + makeNewDescription(panel); + + { + buttonsPanel = new JPanel(); + buttonsPanel.setLayout(new BoxLayout(buttonsPanel, BoxLayout.X_AXIS)); + buttonsPanel.setOpaque(false); + + buttonsPanel.add(Box.createHorizontalStrut(7)); + buttonsPanel.add(downgradeChooser); + buttonsPanel.add(Box.createHorizontalStrut(5)); + buttonsPanel.add(downgradeButton); + + buttonsPanel.add(Box.createHorizontalGlue()); + + buttonsPanel.add(versionToInstallChooser); + buttonsPanel.add(Box.createHorizontalStrut(5)); + buttonsPanel.add(installButton); + buttonsPanel.add(Box.createHorizontalStrut(5)); + buttonsPanel.add(removeButton); + buttonsPanel.add(Box.createHorizontalStrut(5)); + buttonsPanel.add(Box.createHorizontalStrut(15)); + + panel.add(buttonsPanel); + } + + { + inactiveButtonsPanel = new JPanel(); + inactiveButtonsPanel.setLayout(new BoxLayout(inactiveButtonsPanel, BoxLayout.X_AXIS)); + inactiveButtonsPanel.setOpaque(false); + + int height = installButton.getMinimumSize().height; + inactiveButtonsPanel.add(Box.createVerticalStrut(height)); + inactiveButtonsPanel.add(Box.createGlue()); + + statusLabel = new JLabel(" "); + inactiveButtonsPanel.add(statusLabel); + inactiveButtonsPanel.add(Box.createHorizontalStrut(15)); + + panel.add(inactiveButtonsPanel); + } + + panel.add(Box.createVerticalStrut(15)); + } + + private JTextPane makeNewDescription(JPanel panel) { + if (panel.getComponentCount() > 0) { + panel.remove(0); + } + JTextPane description = new JTextPane(); + description.setInheritsPopupMenu(true); + Insets margin = description.getMargin(); + margin.bottom = 0; + description.setMargin(margin); + description.setContentType("text/html"); + Document doc = description.getDocument(); + if (doc instanceof HTMLDocument) { + HTMLDocument html = (HTMLDocument) doc; + StyleSheet stylesheet = html.getStyleSheet(); + stylesheet.addRule("body { margin: 0; padding: 0;" + + "font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;" + + "font-size: 100%;" + "font-size: 0.95em; }"); + } + description.setOpaque(false); + description.setBorder(new EmptyBorder(4, 7, 7, 7)); + description.setHighlighter(null); + description.setEditable(false); + description.addHyperlinkListener(new HyperlinkListener() { + @Override + public void hyperlinkUpdate(HyperlinkEvent e) { + if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { + Base.openURL(e.getDescription()); + } + } + }); + description.addKeyListener(new DelegatingKeyListener(parentTable)); + panel.add(description, 0); + return description; + } + + protected void onRemove(ContributedPlatform contributedPlatform) { + // Empty + } + + protected void onInstall(ContributedPlatform contributedPlatform, ContributedPlatform installed) { + // Empty + } + + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, + boolean hasFocus, int row, + int column) { + parentTable = table; + setEnabled(false); + Component component = getUpdatedCellComponent(value, isSelected, row, false); + if (row % 2 == 0) { + component.setBackground(new Color(236, 241, 241)); //#ecf1f1 + } else { + component.setBackground(new Color(255, 255, 255)); + } + + int height = new Double(component.getPreferredSize().getHeight()).intValue(); + if (table.getRowHeight(row) < height) { + table.setRowHeight(row, height); + } + + return component; + } + + private ContributionIndexTableModel.ContributedPlatformReleases editorValue; + private JTable parentTable; + + @Override + public Object getCellEditorValue() { + return editorValue; + } + + @Override + public Component getTableCellEditorComponent(JTable table, Object value, + boolean isSelected, int row, + int column) { + parentTable = table; + editorValue = (ContributionIndexTableModel.ContributedPlatformReleases) value; + setEnabled(true); + + final ContributedPlatform installed = editorValue.getInstalled(); + + java.util.List releases = new LinkedList(editorValue.releases); + java.util.List uninstalledReleases = new LinkedList(Collections2.filter(releases, Predicates.not(new InstalledPredicate()))); + + java.util.List installedBuiltIn = new LinkedList(Collections2.filter(releases, Predicates.and(new InstalledPredicate(), new BuiltInPredicate()))); + + if (installed != null && !installedBuiltIn.contains(installed)) { + uninstalledReleases.addAll(installedBuiltIn); + } + + Collections.sort(uninstalledReleases, new ReverseComparator(new DownloadableContributionVersionComparator())); + + downgradeChooser.removeAllItems(); + downgradeChooser.addItem(_("Select version")); + + final java.util.List uninstalledPreviousReleases = Lists.newLinkedList(); + final java.util.List uninstalledNewerReleases = Lists.newLinkedList(); + + final VersionComparator versionComparator = new VersionComparator(); + Lists.newLinkedList(Lists.transform(uninstalledReleases, new Function() { + @Override + public ContributedPlatform apply(ContributedPlatform input) { + if (installed == null || versionComparator.greaterThan(installed.getParsedVersion(), input.getParsedVersion())) { + uninstalledPreviousReleases.add(input); + } else { + uninstalledNewerReleases.add(input); + } + + return input; + } + })); + for (ContributedPlatform release : uninstalledNewerReleases) { + downgradeChooser.addItem(release); + } + for (ContributedPlatform release : uninstalledPreviousReleases) { + downgradeChooser.addItem(release); + } + + downgradeChooser.setVisible(installed != null && (!uninstalledPreviousReleases.isEmpty() || uninstalledNewerReleases.size() > 1)); + downgradeButton.setVisible(installed != null && (!uninstalledPreviousReleases.isEmpty() || uninstalledNewerReleases.size() > 1)); + + versionToInstallChooser.removeAllItems(); + for (ContributedPlatform release : uninstalledReleases) { + versionToInstallChooser.addItem(release); + } + versionToInstallChooser.setVisible(installed == null && uninstalledReleases.size() > 1); + + Component component = getUpdatedCellComponent(value, true, row, !installedBuiltIn.isEmpty()); + component.setBackground(new Color(218, 227, 227)); //#dae3e3 + return component; + } + + private Component getUpdatedCellComponent(Object value, boolean isSelected, int row, boolean hasBuiltInRelease) { + ContributionIndexTableModel.ContributedPlatformReleases releases = (ContributionIndexTableModel.ContributedPlatformReleases) value; + + JTextPane description = makeNewDescription(panel); + + //FIXME: happens on macosx, don't know why + if (releases == null) { + return panel; + } + + ContributedPlatform selected = releases.getSelected(); + ContributedPlatform installed = releases.getInstalled(); + + boolean removable, installable, upgradable; + if (installed == null) { + installable = true; + removable = false; + upgradable = false; + } else { + installable = false; + removable = !installed.isReadOnly() && !hasBuiltInRelease; + upgradable = new DownloadableContributionVersionComparator().compare(selected, installed) > 0; + } + if (installable) { + installButton.setText(_("Install")); + } + if (upgradable) { + installButton.setText(_("Update")); + } + installButton.setVisible(installable || upgradable); + installButtonPlaceholder.setVisible(!(installable || upgradable)); + removeButton.setVisible(removable); + removeButtonPlaceholder.setVisible(!removable); + + String desc = ""; + desc += "" + selected.getName() + ""; + if (installed != null && installed.isReadOnly()) { + desc += " Built-In "; + } + + String author = selected.getParentPackage().getMaintainer(); + if (author != null && !author.isEmpty()) { + desc += " " + format("by {0}", author); + } + if (installed != null) { + desc += " " + format(_("version {0}"), installed.getParsedVersion()) + " INSTALLED"; + } + desc += "
"; + + desc += _("Boards included in this package:") + "
"; + for (ContributedBoard board : selected.getBoards()) { + desc += board.getName() + ", "; + } + desc = desc.substring(0, desc.lastIndexOf(',')) + ".
"; + + ContributedHelp help = null; + if (selected.getHelp() != null) { + help = selected.getHelp(); + } else if (selected.getParentPackage().getHelp() != null) { + help = selected.getParentPackage().getHelp(); + } + if (help != null) { + String url = help.getOnline(); + if (url != null && !url.isEmpty()) { + desc += " " + format("Online help
", url); + } + } + + String url = selected.getParentPackage().getWebsiteURL(); + if (url != null && !url.isEmpty()) { + desc += " " + format("More info", url); + } + + desc += ""; + description.setText(desc); + description.setBackground(Color.WHITE); + + // for modelToView to work, the text area has to be sized. It doesn't + // matter if it's visible or not. + + // See: + // http://stackoverflow.com/questions/3081210/how-to-set-jtextarea-to-have-height-that-matches-the-size-of-a-text-it-contains + int width = parentTable.getBounds().width; + setJTextPaneDimensionToFitContainedText(description, width); + + if (isSelected) { + panel.setBackground(parentTable.getSelectionBackground()); + panel.setForeground(parentTable.getSelectionForeground()); + } else { + panel.setBackground(parentTable.getBackground()); + panel.setForeground(parentTable.getForeground()); + } + + return panel; + } + + private Timer enabler = new Timer(100, new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + enable(true); + enabler.stop(); + } + }); + + @Override + public void setEnabled(boolean enabled) { + enable(false); + if (enabled) { + enabler.start(); + } else { + enabler.stop(); + } + buttonsPanel.setVisible(enabled); + inactiveButtonsPanel.setVisible(!enabled); + } + + public void enable(boolean enabled) { + installButton.setEnabled(enabled); + removeButton.setEnabled(enabled); + } + + public void setStatus(String status) { + statusLabel.setText(status); + } + + public void invalidate() { + panel.invalidate(); + } + +} diff --git a/app/src/cc/arduino/contributions/packages/ui/ContributionIndexTableModel.java b/app/src/cc/arduino/contributions/packages/ui/ContributionIndexTableModel.java new file mode 100644 index 000000000..25c1506d4 --- /dev/null +++ b/app/src/cc/arduino/contributions/packages/ui/ContributionIndexTableModel.java @@ -0,0 +1,224 @@ +/* + * This file is part of Arduino. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ +package cc.arduino.contributions.packages.ui; + +import cc.arduino.contributions.DownloadableContributionBuiltInAtTheBottomComparator; +import cc.arduino.contributions.filters.InstalledPredicate; +import cc.arduino.contributions.packages.ContributedPackage; +import cc.arduino.contributions.packages.ContributedPlatform; +import cc.arduino.contributions.packages.ContributionsIndexer; +import cc.arduino.contributions.ui.FilteredAbstractTableModel; +import com.google.common.base.Predicate; +import com.google.common.base.Predicates; +import com.google.common.collect.Collections2; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +@SuppressWarnings("serial") +public class ContributionIndexTableModel extends FilteredAbstractTableModel { + + public final static int DESCRIPTION_COL = 0; + + public static class ContributedPlatformReleases { + public final ContributedPackage packager; + public final String arch; + public final List releases; + public final List versions; + public ContributedPlatform selected = null; + + public ContributedPlatformReleases(ContributedPlatform platform) { + this.packager = platform.getParentPackage(); + this.arch = platform.getArchitecture(); + this.releases = new LinkedList(); + this.versions = new LinkedList(); + add(platform); + } + + public boolean shouldContain(ContributedPlatform platform) { + if (platform.getParentPackage() != packager) + return false; + return platform.getArchitecture().equals(arch); + } + + public void add(ContributedPlatform platform) { + releases.add(platform); + String version = platform.getParsedVersion(); + if (version != null) { + versions.add(version); + } + selected = getLatest(); + } + + public ContributedPlatform getInstalled() { + List installedReleases = new LinkedList(Collections2.filter(releases, new InstalledPredicate())); + Collections.sort(installedReleases, new DownloadableContributionBuiltInAtTheBottomComparator()); + + if (installedReleases.isEmpty()) { + return null; + } + + return installedReleases.get(0); + } + + public ContributedPlatform getLatest() { + return getLatestOf(releases); + } + + public ContributedPlatform getSelected() { + return selected; + } + + public void select(ContributedPlatform value) { + for (ContributedPlatform plat : releases) { + if (plat == value) { + selected = plat; + return; + } + } + } + } + + private List contributions = new ArrayList(); + + private String[] columnNames = {"Description"}; + + private Class[] columnTypes = {ContributedPlatform.class}; + + private ContributionsIndexer indexer; + + public void setIndexer(ContributionsIndexer indexer) { + this.indexer = indexer; + } + + public void updateIndexFilter(String filters[], Predicate... additionalFilters) { + contributions.clear(); + Predicate filter = Predicates.and(additionalFilters); + for (ContributedPackage pack : indexer.getPackages()) { + for (ContributedPlatform platform : pack.getPlatforms()) { + if (!filter.apply(platform)) { + continue; + } + if (!stringContainsAll(platform.getName(), filters)) + continue; + addContribution(platform); + } + } + fireTableDataChanged(); + } + + /** + * Check if string contains all the substrings in set. The + * compare is case insensitive. + * + * @param string + * @param set + * @return true if all the strings in set are contained in + * string. + */ + private boolean stringContainsAll(String string, String set[]) { + if (set == null) + return true; + for (String s : set) { + if (!string.toLowerCase().contains(s.toLowerCase())) + return false; + } + return true; + } + + private void addContribution(ContributedPlatform platform) { + for (ContributedPlatformReleases contribution : contributions) { + if (!contribution.shouldContain(platform)) + continue; + contribution.add(platform); + return; + } + + contributions.add(new ContributedPlatformReleases(platform)); + } + + @Override + public int getColumnCount() { + return columnNames.length; + } + + @Override + public int getRowCount() { + return contributions.size(); + } + + @Override + public String getColumnName(int column) { + return columnNames[column]; + } + + @Override + public Class getColumnClass(int colum) { + return columnTypes[colum]; + } + + @Override + public void setValueAt(Object value, int row, int col) { + if (col == DESCRIPTION_COL) { + fireTableCellUpdated(row, col); + } + } + + @Override + public Object getValueAt(int row, int col) { + if (row >= contributions.size()) { + return null; + } + ContributedPlatformReleases contribution = contributions.get(row); + if (col == DESCRIPTION_COL) { + return contribution;// .getSelected(); + } + return null; + } + + @Override + public boolean isCellEditable(int row, int col) { + return col == DESCRIPTION_COL; + } + + public ContributedPlatformReleases getReleases(int row) { + return contributions.get(row); + } + + public ContributedPlatform getSelectedRelease(int row) { + return contributions.get(row).getSelected(); + } + + public void update() { + fireTableDataChanged(); + } + +} diff --git a/app/src/cc/arduino/contributions/packages/ui/ContributionManagerUI.java b/app/src/cc/arduino/contributions/packages/ui/ContributionManagerUI.java new file mode 100644 index 000000000..af4525235 --- /dev/null +++ b/app/src/cc/arduino/contributions/packages/ui/ContributionManagerUI.java @@ -0,0 +1,229 @@ +/* + * This file is part of Arduino. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ +package cc.arduino.contributions.packages.ui; + +import cc.arduino.contributions.packages.ContributedPlatform; +import cc.arduino.contributions.packages.ContributionInstaller; +import cc.arduino.contributions.packages.ContributionsIndexer; +import cc.arduino.contributions.packages.DownloadableContribution; +import cc.arduino.contributions.ui.*; +import cc.arduino.utils.Progress; +import processing.app.I18n; + +import javax.swing.*; +import java.awt.*; +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; + +import static processing.app.I18n._; + +@SuppressWarnings("serial") +public class ContributionManagerUI extends InstallerJDialog { + + // private ContributedPlatformTableCell cellEditor; + + @Override + protected FilteredAbstractTableModel createContribModel() { + return new ContributionIndexTableModel(); + } + + private ContributionIndexTableModel getContribModel() { + return (ContributionIndexTableModel) contribModel; + } + + @Override + protected InstallerTableCell createCellRenderer() { + return new ContributedPlatformTableCell(); + } + + @Override + protected InstallerTableCell createCellEditor() { + return new ContributedPlatformTableCell() { + @Override + protected void onInstall(ContributedPlatform selected, ContributedPlatform installed) { + if (selected.isReadOnly()) { + onRemovePressed(installed, false); + } else { + onInstallPressed(selected, installed); + } + } + + @Override + protected void onRemove(ContributedPlatform installedPlatform) { + onRemovePressed(installedPlatform, true); + } + }; + } + + public ContributionManagerUI(Frame parent) { + super(parent, _("Boards Manager"), Dialog.ModalityType.APPLICATION_MODAL, _("Unable to reach Arduino.cc due to possible network issues.")); + } + + public void setIndexer(ContributionsIndexer indexer) { + DropdownItem previouslySelectedCategory = (DropdownItem) categoryChooser.getSelectedItem(); + + categoryChooser.removeActionListener(categoryChooserActionListener); + + getContribModel().setIndexer(indexer); + + categoryFilter = null; + categoryChooser.removeAllItems(); + + filterField.setEnabled(getContribModel().getRowCount() > 0); + + categoryChooser.addActionListener(categoryChooserActionListener); + + // Enable categories combo only if there are two or more choices + categoryChooser.addItem(new DropdownAllCoresItem()); + Collection categories = indexer.getCategories(); + for (String s : categories) { + categoryChooser.addItem(new DropdownCoreOfCategoryItem(s)); + } + if (previouslySelectedCategory != null) { + categoryChooser.setSelectedItem(previouslySelectedCategory); + } else { + categoryChooser.setSelectedIndex(0); + } + + // Create ConstributionInstaller tied with the provided index + installer = new ContributionInstaller(indexer) { + @Override + public void onProgress(Progress progress) { + setProgress(progress); + } + }; + } + + public void setProgress(Progress progress) { + progressBar.setValue(progress); + } + + /* + * Installer methods follows + */ + + private ContributionInstaller installer; + private Thread installerThread = null; + + @Override + public void onCancelPressed() { + super.onCancelPressed(); + if (installerThread != null) { + installerThread.interrupt(); + } + } + + @Override + public void onUpdatePressed() { + super.onUpdatePressed(); + installerThread = new Thread(new Runnable() { + @Override + public void run() { + try { + setProgressVisible(true, ""); + List downloadedPackageIndexFiles = installer.updateIndex(); + installer.deleteUnknownFiles(downloadedPackageIndexFiles); + onIndexesUpdated(); + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + setProgressVisible(false, ""); + } + } + }); + installerThread.setUncaughtExceptionHandler(new InstallerJDialogUncaughtExceptionHandler(this, noConnectionErrorMessage)); + installerThread.start(); + } + + public void onInstallPressed(final ContributedPlatform platformToInstall, final ContributedPlatform platformToRemove) { + clearErrorMessage(); + installerThread = new Thread(new Runnable() { + @Override + public void run() { + List errors = new LinkedList(); + try { + setProgressVisible(true, _("Installing...")); + errors.addAll(installer.install(platformToInstall)); + if (platformToRemove != null && !platformToRemove.isReadOnly()) { + errors.addAll(installer.remove(platformToRemove)); + } + onIndexesUpdated(); + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + setProgressVisible(false, ""); + if (!errors.isEmpty()) { + setErrorMessage(errors.get(0)); + } + } + } + }); + installerThread.setUncaughtExceptionHandler(new InstallerJDialogUncaughtExceptionHandler(this, noConnectionErrorMessage)); + installerThread.start(); + } + + public void onRemovePressed(final ContributedPlatform platform, boolean showWarning) { + clearErrorMessage(); + + if (showWarning) { + int chosenOption = JOptionPane.showConfirmDialog(this, I18n.format(_("Do you want to remove {0}?\nIf you do so you won't be able to use {0} any more."), platform.getName()), _("Please confirm boards deletion"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); + if (chosenOption != JOptionPane.YES_OPTION) { + return; + } + } + + installerThread = new Thread(new Runnable() { + @Override + public void run() { + try { + setProgressVisible(true, _("Removing...")); + installer.remove(platform); + onIndexesUpdated(); + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + setProgressVisible(false, ""); + } + } + }); + installerThread.setUncaughtExceptionHandler(new InstallerJDialogUncaughtExceptionHandler(this, noConnectionErrorMessage)); + installerThread.start(); + } + + /** + * Callback invoked when indexes are updated + * + * @throws Exception + */ + protected void onIndexesUpdated() throws Exception { + // Empty + } + +} diff --git a/app/src/cc/arduino/contributions/packages/ui/DropdownAllCoresItem.java b/app/src/cc/arduino/contributions/packages/ui/DropdownAllCoresItem.java new file mode 100644 index 000000000..d2e318b27 --- /dev/null +++ b/app/src/cc/arduino/contributions/packages/ui/DropdownAllCoresItem.java @@ -0,0 +1,54 @@ +/* + * This file is part of Arduino. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ + +package cc.arduino.contributions.packages.ui; + +import cc.arduino.contributions.filters.NoopPredicate; +import cc.arduino.contributions.packages.ContributedPlatform; +import cc.arduino.contributions.ui.DropdownItem; +import com.google.common.base.Predicate; + +import static processing.app.I18n._; + +public class DropdownAllCoresItem implements DropdownItem { + + public String toString() { + return _("All"); + } + + @Override + public Predicate getFilterPredicate() { + return new NoopPredicate(); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof DropdownAllCoresItem; + } +} diff --git a/app/src/cc/arduino/contributions/packages/ui/DropdownCoreOfCategoryItem.java b/app/src/cc/arduino/contributions/packages/ui/DropdownCoreOfCategoryItem.java new file mode 100644 index 000000000..719b4b9e7 --- /dev/null +++ b/app/src/cc/arduino/contributions/packages/ui/DropdownCoreOfCategoryItem.java @@ -0,0 +1,59 @@ +/* + * This file is part of Arduino. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ + +package cc.arduino.contributions.packages.ui; + +import cc.arduino.contributions.packages.ContributedPlatform; +import cc.arduino.contributions.packages.filters.CategoryPredicate; +import cc.arduino.contributions.ui.DropdownItem; +import com.google.common.base.Predicate; + +public class DropdownCoreOfCategoryItem implements DropdownItem { + + private final String category; + + public DropdownCoreOfCategoryItem(String category) { + this.category = category; + } + + public String toString() { + return category; + } + + @Override + public Predicate getFilterPredicate() { + return new CategoryPredicate(category); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof DropdownCoreOfCategoryItem && ((DropdownCoreOfCategoryItem) obj).category.equals(category); + } + +} diff --git a/app/src/cc/arduino/contributions/ui/DropdownAllItem.java b/app/src/cc/arduino/contributions/ui/DropdownAllItem.java new file mode 100644 index 000000000..a9778b8f0 --- /dev/null +++ b/app/src/cc/arduino/contributions/ui/DropdownAllItem.java @@ -0,0 +1,55 @@ +/* + * This file is part of Arduino. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ + +package cc.arduino.contributions.ui; + +import cc.arduino.contributions.filters.NoopPredicate; +import cc.arduino.contributions.packages.DownloadableContribution; +import cc.arduino.contributions.ui.DropdownItem; +import com.google.common.base.Predicate; + +import static processing.app.I18n._; + +public class DropdownAllItem implements DropdownItem { + + public String toString() { + return _("All"); + } + + @Override + public Predicate getFilterPredicate() { + return new NoopPredicate(); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof DropdownAllItem; + } + +} diff --git a/app/src/cc/arduino/contributions/ui/DropdownItem.java b/app/src/cc/arduino/contributions/ui/DropdownItem.java new file mode 100644 index 000000000..ccd787bcd --- /dev/null +++ b/app/src/cc/arduino/contributions/ui/DropdownItem.java @@ -0,0 +1,38 @@ +/* + * This file is part of Arduino. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ + +package cc.arduino.contributions.ui; + +import com.google.common.base.Predicate; + +public interface DropdownItem { + + Predicate getFilterPredicate(); + +} diff --git a/app/src/cc/arduino/contributions/ui/FilterJTextField.java b/app/src/cc/arduino/contributions/ui/FilterJTextField.java new file mode 100644 index 000000000..a9e7cefee --- /dev/null +++ b/app/src/cc/arduino/contributions/ui/FilterJTextField.java @@ -0,0 +1,117 @@ +/* + * This file is part of Arduino. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ +package cc.arduino.contributions.ui; + +import java.awt.Color; +import java.awt.Font; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; + +import javax.swing.JTextField; +import javax.swing.UIManager; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; + +@SuppressWarnings("serial") +public class FilterJTextField extends JTextField { + private final String filterHint; + + private boolean showingHint; + + public FilterJTextField(String hint) { + super(hint); + filterHint = hint; + + showingHint = true; + updateStyle(); + + addFocusListener(new FocusListener() { + public void focusLost(FocusEvent focusEvent) { + if (getText().isEmpty()) { + showingHint = true; + } + updateStyle(); + } + + public void focusGained(FocusEvent focusEvent) { + if (showingHint) { + showingHint = false; + setText(""); + } + updateStyle(); + } + }); + + getDocument().addDocumentListener(new DocumentListener() { + public void removeUpdate(DocumentEvent e) { + applyFilter(); + } + + public void insertUpdate(DocumentEvent e) { + applyFilter(); + } + + public void changedUpdate(DocumentEvent e) { + applyFilter(); + } + }); + } + + private String lastFilter = ""; + + private void applyFilter() { + String filter = showingHint ? "" : getText(); + filter = filter.toLowerCase(); + + // Replace anything but 0-9, a-z, or : with a space + filter = filter.replaceAll("[^\\x30-\\x39^\\x61-\\x7a^\\x3a]", " "); + + // Fire event only if the filter is changed + if (filter.equals(lastFilter)) + return; + + lastFilter = filter; + onFilter(filter.split(" ")); + } + + protected void onFilter(String[] strings) { + // Empty + } + + public void updateStyle() { + if (showingHint) { + setText(filterHint); + setForeground(Color.gray); + setFont(getFont().deriveFont(Font.ITALIC)); + } else { + setForeground(UIManager.getColor("TextField.foreground")); + setFont(getFont().deriveFont(Font.PLAIN)); + } + } +} diff --git a/app/src/cc/arduino/contributions/ui/FilteredAbstractTableModel.java b/app/src/cc/arduino/contributions/ui/FilteredAbstractTableModel.java new file mode 100644 index 000000000..2d72b306a --- /dev/null +++ b/app/src/cc/arduino/contributions/ui/FilteredAbstractTableModel.java @@ -0,0 +1,62 @@ +/* + * This file is part of Arduino. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ +package cc.arduino.contributions.ui; + +import cc.arduino.contributions.VersionComparator; +import cc.arduino.contributions.packages.DownloadableContribution; +import com.google.common.base.Predicate; + +import javax.swing.table.AbstractTableModel; +import java.util.Collections; +import java.util.Comparator; +import java.util.LinkedList; +import java.util.List; + +public abstract class FilteredAbstractTableModel extends AbstractTableModel { + + abstract public void updateIndexFilter(String[] filters, Predicate... additionalFilters); + + protected static T getLatestOf(List contribs) { + contribs = new LinkedList(contribs); + final VersionComparator versionComparator = new VersionComparator(); + Collections.sort(contribs, new Comparator() { + @Override + public int compare(T contrib1, T contrib2) { + return versionComparator.compare(contrib1.getParsedVersion(), contrib2.getParsedVersion()); + } + }); + + if (contribs.isEmpty()) { + return null; + } + + return contribs.get(contribs.size() - 1); + } + +} diff --git a/app/src/cc/arduino/contributions/ui/InstallerJDialog.java b/app/src/cc/arduino/contributions/ui/InstallerJDialog.java new file mode 100644 index 000000000..ec456cbac --- /dev/null +++ b/app/src/cc/arduino/contributions/ui/InstallerJDialog.java @@ -0,0 +1,301 @@ +/* + * This file is part of Arduino. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ +package cc.arduino.contributions.ui; + +import cc.arduino.contributions.packages.ui.ContributionIndexTableModel; +import cc.arduino.contributions.ui.listeners.AbstractKeyListener; +import com.google.common.base.Predicate; +import com.google.common.base.Predicates; +import com.google.common.collect.Collections2; +import processing.app.Base; +import processing.app.Theme; + +import javax.swing.*; +import javax.swing.border.EmptyBorder; +import javax.swing.table.TableColumn; +import javax.swing.table.TableColumnModel; +import java.awt.*; +import java.awt.event.*; +import java.util.Arrays; +import java.util.Collection; +import java.util.LinkedList; + +import static cc.arduino.contributions.packages.ui.ContributionIndexTableModel.DESCRIPTION_COL; +import static processing.app.I18n._; + +public abstract class InstallerJDialog extends JDialog { + + // Toolbar on top of the window: + // - Categories drop-down menu + protected final JComboBox categoryChooser; + // - Search text-field + protected final FilterJTextField filterField; + protected final JPanel filtersContainer; + // Currently selected category and filters + protected Predicate categoryFilter; + protected String[] filters; + protected final String noConnectionErrorMessage; + + // Real contribution table + protected JTable contribTable; + // Model behind the table + protected FilteredAbstractTableModel contribModel; + + abstract protected FilteredAbstractTableModel createContribModel(); + + abstract protected InstallerTableCell createCellRenderer(); + + abstract protected InstallerTableCell createCellEditor(); + + // Bottom: + // - Progress bar + protected final ProgressJProgressBar progressBar; + protected final Box progressBox; + protected final Box errorMessageBox; + private final JLabel errorMessage; + + public InstallerJDialog(Frame parent, String title, ModalityType applicationModal, String noConnectionErrorMessage) { + super(parent, title, applicationModal); + this.noConnectionErrorMessage = noConnectionErrorMessage; + + setResizable(true); + + Container pane = getContentPane(); + pane.setLayout(new BorderLayout()); + + { + categoryChooser = new JComboBox(); + categoryChooser.setMaximumRowCount(20); + categoryChooser.setEnabled(false); + + filterField = new FilterJTextField(_("Filter your search...")) { + @Override + protected void onFilter(String[] _filters) { + filters = _filters; + if (contribTable.getCellEditor() != null) { + contribTable.getCellEditor().stopCellEditing(); + } + updateIndexFilter(filters, categoryFilter); + } + }; + + filtersContainer = new JPanel(); + filtersContainer.setLayout(new BoxLayout(filtersContainer, BoxLayout.X_AXIS)); + filtersContainer.add(Box.createHorizontalStrut(5)); + filtersContainer.add(new JLabel(_("Type"))); + filtersContainer.add(Box.createHorizontalStrut(5)); + filtersContainer.add(categoryChooser); + filtersContainer.add(Box.createHorizontalStrut(5)); + filtersContainer.add(filterField); + filtersContainer.setBorder(new EmptyBorder(7, 7, 7, 7)); + pane.add(filtersContainer, BorderLayout.NORTH); + } + + contribModel = createContribModel(); + contribTable = new JTable(contribModel); + contribTable.setTableHeader(null); + contribTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + contribTable.setColumnSelectionAllowed(false); + contribTable.setDragEnabled(false); + contribTable.setIntercellSpacing(new Dimension(0, 1)); + contribTable.setShowVerticalLines(false); + contribTable.setSelectionBackground(Theme.getColor("status.notice.bgcolor")); + contribTable.addKeyListener(new AbstractKeyListener() { + + @Override + public void keyReleased(KeyEvent keyEvent) { + if (keyEvent.getKeyCode() != KeyEvent.VK_DOWN && keyEvent.getKeyCode() != KeyEvent.VK_UP) { + return; + } + + if (!contribTable.isEnabled()) { + return; + } + + contribTable.editCellAt(contribTable.getSelectedRow(), contribTable.getSelectedColumn()); + } + }); + + { + TableColumnModel tcm = contribTable.getColumnModel(); + TableColumn col = tcm.getColumn(DESCRIPTION_COL); + col.setCellRenderer(createCellRenderer()); + col.setCellEditor(createCellEditor()); + col.setResizable(true); + } + + { + JScrollPane scrollPane = new JScrollPane(); + scrollPane.setViewportView(contribTable); + scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); + scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + scrollPane.getVerticalScrollBar().setUnitIncrement(7); + pane.add(scrollPane, BorderLayout.CENTER); + } + + pane.add(Box.createHorizontalStrut(10), BorderLayout.WEST); + pane.add(Box.createHorizontalStrut(10), BorderLayout.EAST); + + progressBar = new ProgressJProgressBar(); + progressBar.setStringPainted(true); + progressBar.setString(" "); + progressBar.setVisible(true); + + errorMessage = new JLabel(""); + errorMessage.setForeground(Color.RED); + + { + JButton cancelButton = new JButton(_("Cancel")); + cancelButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent arg0) { + onCancelPressed(); + } + }); + + progressBox = Box.createHorizontalBox(); + progressBox.add(progressBar); + progressBox.add(Box.createHorizontalStrut(5)); + progressBox.add(cancelButton); + + JButton dismissErrorMessageButton = new JButton(_("OK")); + dismissErrorMessageButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent arg0) { + clearErrorMessage(); + } + }); + + errorMessageBox = Box.createHorizontalBox(); + errorMessageBox.add(Box.createHorizontalGlue()); + errorMessageBox.add(errorMessage); + errorMessageBox.add(Box.createHorizontalGlue()); + errorMessageBox.add(dismissErrorMessageButton); + errorMessageBox.setVisible(false); + } + + { + JPanel progressPanel = new JPanel(); + progressPanel.setBorder(new EmptyBorder(7, 7, 7, 7)); + progressPanel.setLayout(new BoxLayout(progressPanel, BoxLayout.Y_AXIS)); + progressPanel.add(progressBox); + progressPanel.add(errorMessageBox); + pane.add(progressPanel, BorderLayout.SOUTH); + } + setProgressVisible(false, ""); + + setMinimumSize(new Dimension(800, 450)); + + setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + + Base.registerWindowCloseKeys(getRootPane(), new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + InstallerJDialog.this.dispatchEvent(new WindowEvent(InstallerJDialog.this, WindowEvent.WINDOW_CLOSING)); + } + }); + + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + onUpdatePressed(); + } + }); + } + + public void updateIndexFilter(String[] filters, Predicate... additionalFilters) { + Collection> notNullAdditionalFilters = Collections2.filter(Arrays.asList(additionalFilters), Predicates.notNull()); + contribModel.updateIndexFilter(filters, notNullAdditionalFilters.toArray(new Predicate[notNullAdditionalFilters.size()])); + } + + public void setErrorMessage(String message) { + errorMessage.setText("" + message + ""); + errorMessageBox.setVisible(true); + } + + public void clearErrorMessage() { + errorMessage.setText(""); + errorMessageBox.setVisible(false); + } + + public void setProgressVisible(boolean visible, String status) { + if (visible) { + setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); + } else { + setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + } + progressBox.setVisible(visible); + + filterField.setEnabled(!visible); + categoryChooser.setEnabled(!visible); + contribTable.setEnabled(!visible); + errorMessageBox.setVisible(false); + if (contribTable.getCellEditor() != null) { + ((InstallerTableCell) contribTable.getCellEditor()).setEnabled(!visible); + ((InstallerTableCell) contribTable.getCellEditor()).setStatus(status); + } + } + + protected final ActionListener categoryChooserActionListener = new ActionListener() { + + @Override + public void actionPerformed(ActionEvent event) { + DropdownItem selected = (DropdownItem) categoryChooser.getSelectedItem(); + if (categoryFilter == null || !categoryFilter.equals(selected)) { + categoryFilter = selected.getFilterPredicate(); + if (contribTable.getCellEditor() != null) { + contribTable.getCellEditor().stopCellEditing(); + } + updateIndexFilter(filters, categoryFilter); + } + } + }; + + public void setFilterText(String filterText) { + for (FocusListener listener : filterField.getFocusListeners()) { + listener.focusGained(new FocusEvent(filterField, FocusEvent.FOCUS_GAINED)); + } + filterField.setText(filterText); + } + + /** + * Action performed when the Cancel button is pressed. + */ + protected void onCancelPressed() { + clearErrorMessage(); + } + + /** + * Action performed when the "Update List" button is pressed. + */ + protected void onUpdatePressed() { + clearErrorMessage(); + } + +} diff --git a/app/src/cc/arduino/contributions/ui/InstallerJDialogUncaughtExceptionHandler.java b/app/src/cc/arduino/contributions/ui/InstallerJDialogUncaughtExceptionHandler.java new file mode 100644 index 000000000..2c8e43dd0 --- /dev/null +++ b/app/src/cc/arduino/contributions/ui/InstallerJDialogUncaughtExceptionHandler.java @@ -0,0 +1,65 @@ +/* + * This file is part of Arduino. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ + +package cc.arduino.contributions.ui; + +import cc.arduino.contributions.ui.InstallerJDialog; + +import javax.swing.*; + +import static processing.app.I18n._; + +public class InstallerJDialogUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler { + + private final InstallerJDialog parent; + private final String connectionErrorMessage; + + public InstallerJDialogUncaughtExceptionHandler(InstallerJDialog parent, String connectionErrorMessage) { + this.parent = parent; + this.connectionErrorMessage = connectionErrorMessage; + } + + @Override + public void uncaughtException(Thread t, final Throwable e) { + String errorMessage = _(e.getMessage().substring(e.getMessage().indexOf(":") + 1)); + if (errorMessage.startsWith("Error downloading")) { + errorMessage = connectionErrorMessage; + } + final String finalErrorMessage = errorMessage; + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + System.err.println(finalErrorMessage); + e.printStackTrace(); + } + }); + parent.setErrorMessage(finalErrorMessage); + } + +} diff --git a/app/src/cc/arduino/contributions/ui/InstallerTableCell.java b/app/src/cc/arduino/contributions/ui/InstallerTableCell.java new file mode 100644 index 000000000..eb0187632 --- /dev/null +++ b/app/src/cc/arduino/contributions/ui/InstallerTableCell.java @@ -0,0 +1,61 @@ +/* + * This file is part of Arduino. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ +package cc.arduino.contributions.ui; + +import javax.swing.*; +import javax.swing.table.TableCellEditor; +import javax.swing.table.TableCellRenderer; +import javax.swing.text.BadLocationException; +import java.awt.*; + +public abstract class InstallerTableCell extends AbstractCellEditor implements TableCellEditor, TableCellRenderer { + + public void setEnabled(boolean b) { + } + + public void setStatus(String s) { + } + + protected void setJTextPaneDimensionToFitContainedText(JTextPane jTextPane, int width) { + Dimension minimumDimension = new Dimension(width, 10); + jTextPane.setPreferredSize(minimumDimension); + jTextPane.setSize(minimumDimension); + + try { + Rectangle r = jTextPane.modelToView(jTextPane.getDocument().getLength()); + //r.height += jTextPane.modelToView(0).y; // add margins + Dimension d = new Dimension(minimumDimension.width, r.y + r.height); + jTextPane.setPreferredSize(d); + } catch (BadLocationException e) { + throw new RuntimeException(e); + } + + } + +} diff --git a/app/src/cc/arduino/contributions/ui/ProgressJProgressBar.java b/app/src/cc/arduino/contributions/ui/ProgressJProgressBar.java new file mode 100644 index 000000000..ffe43a25a --- /dev/null +++ b/app/src/cc/arduino/contributions/ui/ProgressJProgressBar.java @@ -0,0 +1,44 @@ +/* + * This file is part of Arduino. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ +package cc.arduino.contributions.ui; + +import javax.swing.JProgressBar; + +import cc.arduino.utils.Progress; + +@SuppressWarnings("serial") +public class ProgressJProgressBar extends JProgressBar { + + public void setValue(Progress p) { + setValue((int) p.getProgress()); + if (p.getStatus() != null) + setString(p.getStatus()); + } + +} diff --git a/app/src/cc/arduino/contributions/ui/listeners/AbstractKeyListener.java b/app/src/cc/arduino/contributions/ui/listeners/AbstractKeyListener.java new file mode 100644 index 000000000..3562a89a8 --- /dev/null +++ b/app/src/cc/arduino/contributions/ui/listeners/AbstractKeyListener.java @@ -0,0 +1,52 @@ +/* + * This file is part of Arduino. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ + +package cc.arduino.contributions.ui.listeners; + +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; + +public abstract class AbstractKeyListener implements KeyListener { + + @Override + public void keyTyped(KeyEvent keyEvent) { + + } + + @Override + public void keyPressed(KeyEvent keyEvent) { + + } + + @Override + public void keyReleased(KeyEvent keyEvent) { + + } + +} diff --git a/app/src/cc/arduino/contributions/ui/listeners/DelegatingKeyListener.java b/app/src/cc/arduino/contributions/ui/listeners/DelegatingKeyListener.java new file mode 100644 index 000000000..161b67eb1 --- /dev/null +++ b/app/src/cc/arduino/contributions/ui/listeners/DelegatingKeyListener.java @@ -0,0 +1,76 @@ +/* + * This file is part of Arduino. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ + +package cc.arduino.contributions.ui.listeners; + +import java.awt.*; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; + +public class DelegatingKeyListener implements KeyListener { + + private final Component delegate; + + public DelegatingKeyListener(Component delegate) { + this.delegate = delegate; + } + + @Override + public void keyTyped(final KeyEvent keyEvent) { + if (delegate.getKeyListeners() == null) { + return; + } + + for (KeyListener listener : delegate.getKeyListeners()) { + listener.keyTyped(keyEvent); + } + } + + @Override + public void keyPressed(KeyEvent keyEvent) { + if (delegate.getKeyListeners() == null) { + return; + } + + for (KeyListener listener : delegate.getKeyListeners()) { + listener.keyPressed(keyEvent); + } + } + + @Override + public void keyReleased(KeyEvent keyEvent) { + if (delegate.getKeyListeners() == null) { + return; + } + + for (KeyListener listener : delegate.getKeyListeners()) { + listener.keyReleased(keyEvent); + } + } +} diff --git a/app/src/cc/arduino/packages/MonitorFactory.java b/app/src/cc/arduino/packages/MonitorFactory.java index 5ece88231..0eee5eb6e 100644 --- a/app/src/cc/arduino/packages/MonitorFactory.java +++ b/app/src/cc/arduino/packages/MonitorFactory.java @@ -1,3 +1,32 @@ +/* + * This file is part of Arduino. + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + */ + package cc.arduino.packages; import processing.app.AbstractMonitor; diff --git a/app/src/cc/arduino/packages/formatter/AStyle.java b/app/src/cc/arduino/packages/formatter/AStyle.java index c92d1c5cd..9c61ff2db 100644 --- a/app/src/cc/arduino/packages/formatter/AStyle.java +++ b/app/src/cc/arduino/packages/formatter/AStyle.java @@ -1,11 +1,43 @@ +/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + * This file is part of Arduino. + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + */ + package cc.arduino.packages.formatter; import processing.app.Base; import processing.app.Editor; import processing.app.helpers.FileUtils; -import processing.app.syntax.JEditTextArea; +import processing.app.syntax.SketchTextArea; import processing.app.tools.Tool; +import javax.swing.text.BadLocationException; import java.io.File; import java.io.IOException; @@ -13,7 +45,7 @@ import static processing.app.I18n._; public class AStyle implements Tool { - private static String FORMATTER_CONF = "formatter.conf"; + private static final String FORMATTER_CONF = "formatter.conf"; private final AStyleInterface aStyleInterface; private final String formatterConfiguration; @@ -35,7 +67,7 @@ public class AStyle implements Tool { try { formatterConfiguration = FileUtils.readFileToString(formatterConf); } catch (IOException e) { - // noop + // ignored } this.formatterConfiguration = formatterConfiguration; } @@ -55,17 +87,50 @@ public class AStyle implements Tool { return; } - JEditTextArea textArea = editor.getTextArea(); - int line = textArea.getLineOfOffset(textArea.getCaretPosition()); - int lineOffset = textArea.getCaretPosition() - textArea.getLineStartOffset(line); + SketchTextArea textArea = editor.getTextArea(); + int line = getLineOfOffset(textArea); + int lineOffset = getLineOffset(textArea, line); + + editor.getTextArea().getUndoManager().beginInternalAtomicEdit(); editor.setText(formattedText); editor.getSketch().setModified(true); - textArea.setCaretPosition(Math.min(textArea.getLineStartOffset(line) + lineOffset, textArea.getSafeLineStopOffset(line) - 1)); + editor.getTextArea().getUndoManager().endInternalAtomicEdit(); + + if (line != -1 && lineOffset != -1) { + setCaretPosition(textArea, line, lineOffset); + } + // mark as finished editor.statusNotice(_("Auto Format finished.")); } + private void setCaretPosition(SketchTextArea textArea, int line, int lineOffset) { + try { + textArea.setCaretPosition(Math.min(textArea.getLineStartOffset(line) + lineOffset, textArea.getLineEndOffset(line) - 1)); + } catch (BadLocationException e) { + e.printStackTrace(); + } + } + + private int getLineOffset(SketchTextArea textArea, int line) { + try { + return textArea.getCaretPosition() - textArea.getLineStartOffset(line); + } catch (BadLocationException e) { + e.printStackTrace(); + } + return -1; + } + + private int getLineOfOffset(SketchTextArea textArea) { + try { + return textArea.getLineOfOffset(textArea.getCaretPosition()); + } catch (BadLocationException e) { + e.printStackTrace(); + } + return -1; + } + @Override public String getMenuTitle() { return _("Auto Format"); diff --git a/app/src/cc/arduino/packages/formatter/AStyleInterface.java b/app/src/cc/arduino/packages/formatter/AStyleInterface.java index 8c08c6446..97341f4a0 100644 --- a/app/src/cc/arduino/packages/formatter/AStyleInterface.java +++ b/app/src/cc/arduino/packages/formatter/AStyleInterface.java @@ -1,3 +1,32 @@ +/* + * This file is part of Arduino. + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + */ + package cc.arduino.packages.formatter; import processing.app.Base; diff --git a/app/src/cc/arduino/view/Event.java b/app/src/cc/arduino/view/Event.java index 4cc2cd278..5a050dfb3 100644 --- a/app/src/cc/arduino/view/Event.java +++ b/app/src/cc/arduino/view/Event.java @@ -48,10 +48,7 @@ public class Event extends ActionEvent { @Override public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append(super.toString()); - sb.append("\n").append(payload.toString()); - return sb.toString(); + return super.toString() + "\n" + payload.toString(); } } diff --git a/app/src/cc/arduino/view/SplashScreenHelper.java b/app/src/cc/arduino/view/SplashScreenHelper.java new file mode 100644 index 000000000..7d5948fec --- /dev/null +++ b/app/src/cc/arduino/view/SplashScreenHelper.java @@ -0,0 +1,96 @@ +/* + * This file is part of Arduino. + * + * Code inspired by this tutorial http://wiki.netbeans.org/Splash_Screen_Beginner_Tutorial. License says "You may modify and use it as you wish." + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ + +package cc.arduino.view; + +import java.awt.*; +import java.awt.geom.Rectangle2D; +import java.util.Map; + +public class SplashScreenHelper { + + private final Map desktopHints; + private final SplashScreen splash; + private Rectangle2D.Double splashTextArea; + private Graphics2D splashGraphics; + + public SplashScreenHelper(SplashScreen splash) { + this.splash = splash; + Toolkit tk = Toolkit.getDefaultToolkit(); + desktopHints = (Map) tk.getDesktopProperty("awt.font.desktophints"); + } + + public void splashText(String str) { + if (splash == null) { + printText(str); + return; + } + if (!splash.isVisible()) { + return; + } + + if (splashTextArea == null) { + // stake out some area for our status information + splashTextArea = new Rectangle2D.Double(0, 300, 520, 30); + + // create the Graphics environment for drawing status info + splashGraphics = splash.createGraphics(); + + if (desktopHints != null) { + splashGraphics.addRenderingHints(desktopHints); + } + } + + // erase the last status text + splashGraphics.setPaint(new Color(245, 245, 245)); + splashGraphics.fill(splashTextArea); + + // draw the text + splashGraphics.setPaint(Color.BLACK); + FontMetrics metrics = splashGraphics.getFontMetrics(); + splashGraphics.drawString(str, (int) splashTextArea.getX() + 10, (int) splashTextArea.getY() + (30 - metrics.getHeight()) + 4); + + // make sure it's displayed + splash.update(); + } + + public void close() { + if (splash == null) { + return; + } + splash.close(); + } + + private void printText(String str) { + System.out.println(str); + } + +} diff --git a/app/src/cc/arduino/view/ShowUncertifiedBoardWarning.java b/app/src/cc/arduino/view/StubMenuListener.java similarity index 64% rename from app/src/cc/arduino/view/ShowUncertifiedBoardWarning.java rename to app/src/cc/arduino/view/StubMenuListener.java index 974608356..dd9654b82 100644 --- a/app/src/cc/arduino/view/ShowUncertifiedBoardWarning.java +++ b/app/src/cc/arduino/view/StubMenuListener.java @@ -1,6 +1,8 @@ /* * This file is part of Arduino. * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + * * Arduino 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 @@ -23,37 +25,25 @@ * the GNU General Public License. This exception does not however * invalidate any other reasons why the executable file might be covered by * the GNU General Public License. - * - * Copyright 2015 Arduino LLC (http://www.arduino.cc/) */ package cc.arduino.view; -import processing.app.Preferences; +import javax.swing.event.MenuEvent; +import javax.swing.event.MenuListener; -import java.awt.*; +public class StubMenuListener implements MenuListener { -public class ShowUncertifiedBoardWarning implements Runnable { - - private final Frame parent; - - public ShowUncertifiedBoardWarning(Frame parent) { - this.parent = parent; + @Override + public void menuSelected(MenuEvent e) { } @Override - public void run() { - UncertifiedBoardWarning uncertifiedBoardWarning = new UncertifiedBoardWarning(parent, new EventListener() { - @Override - public void eventHappened(cc.arduino.view.Event event) { - if (!"uncertified_board_warning_ok_pressed".equals(event.getActionCommand())) { - return; - } - Preferences.set("uncertifiedBoardWarning_dontShowMeAgain", event.getPayload().get("dontShowMeAgain").toString()); - } - }); - uncertifiedBoardWarning.setLocationRelativeTo(parent); - uncertifiedBoardWarning.setVisible(true); + public void menuDeselected(MenuEvent e) { + } + + @Override + public void menuCanceled(MenuEvent e) { } } diff --git a/app/src/cc/arduino/view/UncertifiedBoardWarning.java b/app/src/cc/arduino/view/UncertifiedBoardWarning.java deleted file mode 100644 index 8d53add20..000000000 --- a/app/src/cc/arduino/view/UncertifiedBoardWarning.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * This file is part of Arduino. - * - * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA - * - * As a special exception, you may use this file as part of a free software - * library without restriction. Specifically, if other files instantiate - * templates or use macros or inline functions from this file, or you compile - * this file and link it with other files to produce an executable, this - * file does not by itself cause the resulting executable to be covered by - * the GNU General Public License. This exception does not however - * invalidate any other reasons why the executable file might be covered by - * the GNU General Public License. - * - * Copyright 2015 Arduino LLC (http://www.arduino.cc/) - */ - -package cc.arduino.view; - -import javax.swing.*; -import java.awt.*; - -import static processing.app.I18n._; - -public class UncertifiedBoardWarning extends javax.swing.JDialog { - - private final EventListener listener; - - public UncertifiedBoardWarning(Frame parent, EventListener listener) { - super(parent); - initComponents(); - this.listener = listener; - } - - /** - * This method is called from within the constructor to initialize the form. - * WARNING: Do NOT modify this code. The content of this method is always - * regenerated by the Form Editor. - */ - @SuppressWarnings("unchecked") - // //GEN-BEGIN:initComponents - private void initComponents() { - - jLabel1 = new javax.swing.JLabel(); - dontShowMeAgain = new javax.swing.JCheckBox(); - ok = new javax.swing.JButton(); - - setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); - setTitle(_("Uncertified board")); - setModal(true); - setName("uncertifiedBoardWarning"); // NOI18N - setResizable(false); - - jLabel1.setText("" + _("This board comes from an uncertified manufacturer.") + "
" + _("We won't be able to provide any support if it doesn't work as expected.") + ""); - jLabel1.setVerticalAlignment(javax.swing.SwingConstants.TOP); - - dontShowMeAgain.setText(_("Don't show me again")); - dontShowMeAgain.setName("dontShowMeAgain"); // NOI18N - - ok.setText(_("OK")); - ok.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - okActionPerformed(evt); - } - }); - - javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); - getContentPane().setLayout(layout); - layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) - .addGroup(layout.createSequentialGroup() - .addComponent(dontShowMeAgain) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 206, Short.MAX_VALUE) - .addComponent(ok, javax.swing.GroupLayout.PREFERRED_SIZE, 82, javax.swing.GroupLayout.PREFERRED_SIZE))) - .addContainerGap()) - ); - layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 87, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(dontShowMeAgain) - .addComponent(ok)) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - ); - - pack(); - }//
//GEN-END:initComponents - - private void okActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okActionPerformed - Event event = new Event(evt.getSource(), evt.getID(), "uncertified_board_warning_ok_pressed"); - event.getPayload().put("dontShowMeAgain", dontShowMeAgain.isSelected()); - listener.eventHappened(event); - this.dispose(); - }//GEN-LAST:event_okActionPerformed - - /** - * @param args the command line arguments - */ - public static void main(String args[]) throws Exception { - UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); - /* Create and display the dialog */ - java.awt.EventQueue.invokeLater(new Runnable() { - public void run() { - UncertifiedBoardWarning dialog = new UncertifiedBoardWarning(new javax.swing.JFrame(), new EventListener() { - - @Override - public void eventHappened(Event event) { - System.out.println(event); - } - }); - dialog.addWindowListener(new java.awt.event.WindowAdapter() { - @Override - public void windowClosing(java.awt.event.WindowEvent e) { - System.exit(0); - } - }); - dialog.setVisible(true); - } - }); - } - - // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JCheckBox dontShowMeAgain; - private javax.swing.JLabel jLabel1; - private javax.swing.JButton ok; - // End of variables declaration//GEN-END:variables -} diff --git a/app/src/cc/arduino/view/UncertifiedBoardWarning.form b/app/src/cc/arduino/view/preferences/AdditionalBoardsManagerURLTextArea.form similarity index 51% rename from app/src/cc/arduino/view/UncertifiedBoardWarning.form rename to app/src/cc/arduino/view/preferences/AdditionalBoardsManagerURLTextArea.form index 90ea0a918..0d47750a3 100644 --- a/app/src/cc/arduino/view/UncertifiedBoardWarning.form +++ b/app/src/cc/arduino/view/preferences/AdditionalBoardsManagerURLTextArea.form @@ -3,10 +3,11 @@
- + - - + + + @@ -27,15 +28,16 @@ - + - - - - + + + + + @@ -45,29 +47,50 @@ - + - + - + - + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - + + + + + + + + @@ -76,6 +99,10 @@ + + + + diff --git a/app/src/cc/arduino/view/preferences/AdditionalBoardsManagerURLTextArea.java b/app/src/cc/arduino/view/preferences/AdditionalBoardsManagerURLTextArea.java new file mode 100644 index 000000000..a75e1c8b4 --- /dev/null +++ b/app/src/cc/arduino/view/preferences/AdditionalBoardsManagerURLTextArea.java @@ -0,0 +1,216 @@ +/* + * This file is part of Arduino. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ + +package cc.arduino.view.preferences; + +import com.google.common.base.Function; +import com.google.common.base.Joiner; +import com.google.common.base.Predicate; +import com.google.common.collect.FluentIterable; +import processing.app.Base; + +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowEvent; +import java.util.Arrays; +import java.util.Collection; + +import static processing.app.I18n._; + +public class AdditionalBoardsManagerURLTextArea extends javax.swing.JDialog { + + private ActionListener onOkListener; + + public AdditionalBoardsManagerURLTextArea(Window parent) { + super(parent); + initComponents(); + setLocationRelativeTo(parent); + + Base.registerWindowCloseKeys(getRootPane(), new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + cancelActionPerformed(e); + } + }); + + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + javax.swing.JScrollPane jScrollPane1 = new javax.swing.JScrollPane(); + javax.swing.JButton cancel = new javax.swing.JButton(); + javax.swing.JButton ok = new javax.swing.JButton(); + + setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); + setTitle(_("Additional Boards Manager URLs")); + setModal(true); + setModalExclusionType(java.awt.Dialog.ModalExclusionType.APPLICATION_EXCLUDE); + + additionalBoardsManagerURLs.setColumns(20); + additionalBoardsManagerURLs.setRows(5); + additionalBoardsManagerURLs.setName(""); // NOI18N + jScrollPane1.setViewportView(additionalBoardsManagerURLs); + + cancel.setText(_("Cancel")); + cancel.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + cancelActionPerformed(evt); + } + }); + + ok.setText(_("OK")); + ok.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + okActionPerformed(evt); + } + }); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGap(0, 439, Short.MAX_VALUE) + .addComponent(ok) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(cancel)) + .addComponent(jScrollPane1)) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 141, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(cancel) + .addComponent(ok)) + .addContainerGap()) + ); + + pack(); + }// //GEN-END:initComponents + + private void cancelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelActionPerformed + dispatchEvent(new WindowEvent(this, WindowEvent.WINDOW_CLOSING)); + }//GEN-LAST:event_cancelActionPerformed + + private void okActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okActionPerformed + ActionEvent actionEvent = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, ""); + onOkListener.actionPerformed(actionEvent); + cancelActionPerformed(evt); + }//GEN-LAST:event_okActionPerformed + + /** + * @param args the command line arguments + */ + public static void main(String args[]) { + /* Set the Nimbus look and feel */ + // + /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel. + * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html + */ + try { + for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) { + if ("Nimbus".equals(info.getName())) { + javax.swing.UIManager.setLookAndFeel(info.getClassName()); + break; + } + } + } catch (ClassNotFoundException ex) { + java.util.logging.Logger.getLogger(AdditionalBoardsManagerURLTextArea.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); + } catch (InstantiationException ex) { + java.util.logging.Logger.getLogger(AdditionalBoardsManagerURLTextArea.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); + } catch (IllegalAccessException ex) { + java.util.logging.Logger.getLogger(AdditionalBoardsManagerURLTextArea.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); + } catch (javax.swing.UnsupportedLookAndFeelException ex) { + java.util.logging.Logger.getLogger(AdditionalBoardsManagerURLTextArea.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); + } + // + + /* Create and display the dialog */ + java.awt.EventQueue.invokeLater(new Runnable() { + public void run() { + AdditionalBoardsManagerURLTextArea dialog = new AdditionalBoardsManagerURLTextArea(new javax.swing.JFrame()); + dialog.addWindowListener(new java.awt.event.WindowAdapter() { + @Override + public void windowClosing(java.awt.event.WindowEvent e) { + System.exit(0); + } + }); + dialog.setVisible(true); + } + }); + } + + public void setText(String text) { + Collection urls = splitAndTrim(text, ","); + additionalBoardsManagerURLs.setText(Joiner.on("\n").skipNulls().join(urls)); + } + + private Collection splitAndTrim(String text, String separator) { + Collection urls = Arrays.asList(text.split(separator)); + return FluentIterable.from(urls).transform(new Function() { + @Override + public String apply(String input) { + return input.trim(); + } + }).filter(new Predicate() { + @Override + public boolean apply(String input) { + return !input.isEmpty(); + } + }).toList(); + } + + public String getText() { + Collection urls = splitAndTrim(additionalBoardsManagerURLs.getText(), "\n"); + return Joiner.on(",").skipNulls().join(urls); + } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private final javax.swing.JTextArea additionalBoardsManagerURLs = new javax.swing.JTextArea(); + // End of variables declaration//GEN-END:variables + + public void onOk(ActionListener listener) { + this.onOkListener = listener; + } +} diff --git a/app/src/cc/arduino/view/preferences/Preferences.form b/app/src/cc/arduino/view/preferences/Preferences.form new file mode 100644 index 000000000..828645018 --- /dev/null +++ b/app/src/cc/arduino/view/preferences/Preferences.form @@ -0,0 +1,634 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/app/src/cc/arduino/view/preferences/Preferences.java b/app/src/cc/arduino/view/preferences/Preferences.java new file mode 100644 index 000000000..2d0262970 --- /dev/null +++ b/app/src/cc/arduino/view/preferences/Preferences.java @@ -0,0 +1,770 @@ +/* + * This file is part of Arduino. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ + +package cc.arduino.view.preferences; + +import processing.app.Base; +import processing.app.Editor; +import processing.app.I18n; +import processing.app.PreferencesData; +import processing.app.helpers.FileUtils; +import processing.app.helpers.OSUtils; +import processing.app.legacy.PApplet; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowEvent; +import java.io.File; + +import static processing.app.I18n._; + +public class Preferences extends javax.swing.JDialog { + + private final Language[] languages; + private final Language[] missingLanguages; + private final WarningItem[] warningItems; + private final Base base; + + public static class Language { + + private final String name; + private final String originalName; + private final String isoCode; + + public Language(String name, String originalName, String isoCode) { + this.name = name; + this.originalName = originalName; + this.isoCode = isoCode; + } + + public String toString() { + if (originalName.length() == 0) { + return name; + } + return originalName + " (" + name + ")"; + } + + public String getIsoCode() { + return isoCode; + } + } + + private static class WarningItem { + private final String value; + private final String translation; + + public WarningItem(String value, String translation) { + this.value = value; + this.translation = translation; + } + + public String getValue() { + return value; + } + + @Override + public String toString() { + return translation; + } + } + + public Preferences(Window parent, Base base) { + super(parent); + this.base = base; + + this.languages = new Language[]{ + new Language(_("System Default"), "", ""), + new Language(_("Albanian"), "shqip", "sq"), + new Language(_("Arabic"), "العربية", "ar"), + new Language(_("Aragonese"), "Aragonés", "an"), + new Language(_("Belarusian"), "БеларуÑÐºÐ°Ñ Ð¼Ð¾Ð²Ð°", "be"), + new Language(_("Bulgarian"), "българÑки", "bg"), + new Language(_("Catalan"), "Català", "ca"), + new Language(_("Chinese Simplified"), "简体中文", "zh_CN"), + new Language(_("Chinese Traditional"), "ç¹é«”中文", "zh_TW"), + new Language(_("Croatian"), "Hrvatski", "hr_HR"), + new Language(_("Czech (Czech Republic)"), "Äeský (Czech Republic)", "cs_CZ"), + new Language(_("Danish (Denmark)"), "Dansk (Denmark)", "da_DK"), + new Language(_("Dutch"), "Nederlands", "nl"), + new Language(_("English"), "English", "en"), + new Language(_("English (United Kingdom)"), "English (United Kingdom)", "en_GB"), + new Language(_("Estonian"), "Eesti", "et"), + new Language(_("Estonian (Estonia)"), "Eesti keel", "et_EE"), + new Language(_("Filipino"), "Pilipino", "fil"), + new Language(_("Finnish"), "Suomi", "fi"), + new Language(_("French"), "Français", "fr"), + new Language(_("Canadian French"), "Canadienne-français", "fr_CA"), + new Language(_("Galician"), "Galego", "gl"), + new Language(_("Georgian"), "სáƒáƒ¥áƒáƒ áƒ—ველáƒáƒ¡", "ka_GE"), + new Language(_("German"), "Deutsch", "de_DE"), + new Language(_("Greek"), "ελληνικά", "el_GR"), + new Language(_("Hebrew"), "עברית", "he"), + new Language(_("Hindi"), "हिंदी", "hi"), + new Language(_("Hungarian"), "Magyar", "hu"), + new Language(_("Indonesian"), "Bahasa Indonesia", "id"), + new Language(_("Italian"), "Italiano", "it_IT"), + new Language(_("Japanese"), "日本語", "ja_JP"), + new Language(_("Korean"), "한국어", "ko_KR"), + new Language(_("Latvian"), "LatvieÅ¡u", "lv_LV"), + new Language(_("Lithuaninan"), "Lietuvių Kalba", "lt_LT"), + new Language(_("Norwegian BokmÃ¥l"), "Norsk bokmÃ¥l", "nb_NO"), + new Language(_("Persian"), "ÙØ§Ø±Ø³ÛŒ", "fa"), + new Language(_("Polish"), "JÄ™zyk Polski", "pl"), + new Language(_("Portuguese (Brazil)"), "Português (Brazil)", "pt_BR"), + new Language(_("Portuguese (Portugal)"), "Português (Portugal)", "pt_PT"), + new Language(_("Romanian"), "Română", "ro"), + new Language(_("Russian"), "РуÑÑкий", "ru"), + new Language(_("Slovenian"), "SlovenÅ¡Äina", "sl_SI"), + new Language(_("Spanish"), "Español", "es"), + new Language(_("Swedish"), "Svenska", "sv"), + new Language(_("Tamil"), "தமிழà¯", "ta"), + new Language(_("Turkish"), "Türk", "tr"), + new Language(_("Ukrainian"), "УкраїнÑький", "uk"), + new Language(_("Vietnamese"), "Tiếng Việt", "vi"), + }; + + this.missingLanguages = new Language[]{ + new Language(_("Afrikaans"), "Afrikaans", "af"), + new Language(_("Armenian"), "Õ€Õ¡ÕµÕ¥Ö€Õ¥Õ¶", "hy"), + new Language(_("Asturian"), "Asturianu", "ast"), + new Language(_("Basque"), "Euskara", "eu"), + new Language(_("Bengali (India)"), "বাংলা (India)", "bn_IN"), + new Language(_("Bosnian"), "Bosanski", "bs"), + new Language(_("Burmese (Myanmar)"), "ဗမာစကား", "my_MM"), + new Language(_("Chinese (China)"), "", "zh_CN"), + new Language(_("Chinese (Hong Kong)"), "", "zh_HK"), + new Language(_("Chinese (Taiwan)"), "", "zh_TW"), + new Language(_("Chinese (Taiwan) (Big5)"), "", "zh_TW.Big5"), + new Language(_("Czech"), "Äeský", "cs"), + new Language(_("Danish"), "Dansk", "da"), + new Language(_("Dutch (Netherlands)"), "Nederlands", "nl_NL"), + new Language(_("Galician (Spain)"), "Galego (Spain)", "gl_ES"), + new Language(_("Nepali"), "नेपाली", "ne"), + new Language(_("N'Ko"), "ß’ßžß", "nqo"), + new Language(_("Marathi"), "मराठी", "mr"), + new Language(_("Malay (Malaysia)"), "بهاس ملايو (Malaysia)", "ms_MY"), + new Language(_("Norwegian"), "Norsk", "no"), + new Language(_("Norwegian Nynorsk"), "Norsk Nynorsk", "nn"), + new Language(_("Portugese"), "Português", "pt"), + new Language(_("Persian (Iran)"), "ÙØ§Ø±Ø³ÛŒ (Iran)", "fa_IR"), + new Language(_("Slovak"), "SlovenÄina", "sk"), + new Language(_("Swahili"), "ÙƒÙØ³ÙˆÙŽÙ‡ÙÙ„", "sw"), + new Language(_("Talossan"), "Talossan", "tzl"), + new Language(_("Urdu (Pakistan)"), "اردو (Pakistan)", "ur_PK"), + new Language(_("Western Frisian"), "Western Frisian", "fy"), + }; + + this.warningItems = new WarningItem[]{ + new WarningItem("none", _("None")), + new WarningItem("default", _("Default")), + new WarningItem("more", _("More")), + new WarningItem("all", _("All")) + }; + + initComponents(); + + Base.registerWindowCloseKeys(getRootPane(), new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + cancelButtonActionPerformed(e); + } + }); + + if (!OSUtils.isWindows() || base.getPortableFolder() != null) { + autoAssociateBox.setEnabled(false); + autoAssociateBox.getParent().remove(autoAssociateBox); + } + + showPrerefencesData(); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + javax.swing.JLabel sketchbookLocationLabel = new javax.swing.JLabel(); + sketchbookLocationField = new javax.swing.JTextField(); + javax.swing.JButton browseButton = new javax.swing.JButton(); + javax.swing.JLabel comboLanguageLabel = new javax.swing.JLabel(); + comboLanguage = new JComboBox(languages); + javax.swing.JLabel requiresRestartLabel = new javax.swing.JLabel(); + javax.swing.JLabel fontSizeLabel = new javax.swing.JLabel(); + fontSizeField = new javax.swing.JTextField(); + javax.swing.JLabel showVerboseLabel = new javax.swing.JLabel(); + verboseCompilationBox = new javax.swing.JCheckBox(); + verboseUploadBox = new javax.swing.JCheckBox(); + javax.swing.JLabel comboWarningsLabel = new javax.swing.JLabel(); + comboWarnings = new JComboBox(warningItems); + javax.swing.JPanel proxySettingsPanel = new javax.swing.JPanel(); + javax.swing.JLabel proxyHTTPServerLabel = new javax.swing.JLabel(); + proxyHTTPServer = new javax.swing.JTextField(); + javax.swing.JLabel proxyHTTPPortLabel = new javax.swing.JLabel(); + proxyHTTPPort = new javax.swing.JTextField(); + javax.swing.JLabel proxyHTTPSServerLabel = new javax.swing.JLabel(); + proxyHTTPSServer = new javax.swing.JTextField(); + javax.swing.JLabel proxyHTTPSPortLabel = new javax.swing.JLabel(); + proxyHTTPSPort = new javax.swing.JTextField(); + javax.swing.JLabel proxyUserLabel = new javax.swing.JLabel(); + proxyUser = new javax.swing.JTextField(); + javax.swing.JLabel proxyPasswordLabel = new javax.swing.JLabel(); + proxyPassword = new javax.swing.JPasswordField(); + javax.swing.JLabel additionalBoardsManagerLabel = new javax.swing.JLabel(); + additionalBoardsManagerField = new javax.swing.JTextField(); + javax.swing.JButton extendedAdditionalUrlFieldWindow = new javax.swing.JButton(); + javax.swing.JLabel morePreferencesLabel = new javax.swing.JLabel(); + preferencesFileLabel = new javax.swing.JLabel(); + javax.swing.JLabel arduinoNotRunningLabel = new javax.swing.JLabel(); + javax.swing.JButton okButton = new javax.swing.JButton(); + javax.swing.JButton cancelButton = new javax.swing.JButton(); + javax.swing.JPanel checkboxesContainer = new javax.swing.JPanel(); + displayLineNumbersBox = new javax.swing.JCheckBox(); + enableCodeFoldingBox = new javax.swing.JCheckBox(); + verifyUploadBox = new javax.swing.JCheckBox(); + externalEditorBox = new javax.swing.JCheckBox(); + checkUpdatesBox = new javax.swing.JCheckBox(); + updateExtensionBox = new javax.swing.JCheckBox(); + autoAssociateBox = new javax.swing.JCheckBox(); + saveVerifyUploadBox = new javax.swing.JCheckBox(); + + setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); + setTitle(_("Preferences")); + setModal(true); + setResizable(false); + + sketchbookLocationLabel.setText(_("Sketchbook location:")); + + sketchbookLocationField.setColumns(40); + + browseButton.setText(I18n.PROMPT_BROWSE); + browseButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + browseButtonActionPerformed(evt); + } + }); + + comboLanguageLabel.setText(_("Editor language: ")); + + requiresRestartLabel.setText(_(" (requires restart of Arduino)")); + + fontSizeLabel.setText(_("Editor font size: ")); + + fontSizeField.setColumns(4); + + showVerboseLabel.setText(_("Show verbose output during: ")); + + verboseCompilationBox.setText(_("compilation ")); + + verboseUploadBox.setText(_("upload")); + + comboWarningsLabel.setText(_("Compiler warnings: ")); + + proxySettingsPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(_("Proxy Settings"))); + + proxyHTTPServerLabel.setText(_("Server (HTTP):")); + + proxyHTTPServer.setColumns(10); + + proxyHTTPPortLabel.setText(_("Port (HTTP):")); + + proxyHTTPPort.setColumns(10); + + proxyHTTPSServerLabel.setText(_("Server (HTTPS):")); + + proxyHTTPSServer.setColumns(10); + + proxyHTTPSPortLabel.setText(_("Port (HTTPS):")); + + proxyHTTPSPort.setColumns(10); + + proxyUserLabel.setText(_("Username:")); + + proxyUser.setColumns(10); + + proxyPasswordLabel.setText(_("Password:")); + + proxyPassword.setColumns(10); + + javax.swing.GroupLayout proxySettingsPanelLayout = new javax.swing.GroupLayout(proxySettingsPanel); + proxySettingsPanel.setLayout(proxySettingsPanelLayout); + proxySettingsPanelLayout.setHorizontalGroup( + proxySettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(proxySettingsPanelLayout.createSequentialGroup() + .addContainerGap() + .addGroup(proxySettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(proxySettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(proxyHTTPSServerLabel) + .addGroup(proxySettingsPanelLayout.createSequentialGroup() + .addGap(8, 8, 8) + .addComponent(proxyHTTPServerLabel))) + .addComponent(proxyUserLabel)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(proxySettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(proxyHTTPServer) + .addComponent(proxyHTTPSServer) + .addComponent(proxyUser, javax.swing.GroupLayout.Alignment.TRAILING)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(proxySettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(proxyHTTPSPortLabel) + .addComponent(proxyPasswordLabel, javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(proxyHTTPPortLabel, javax.swing.GroupLayout.Alignment.TRAILING)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(proxySettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(proxyHTTPSPort, javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(proxyHTTPPort, javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(proxyPassword, javax.swing.GroupLayout.Alignment.LEADING)) + .addContainerGap()) + ); + proxySettingsPanelLayout.setVerticalGroup( + proxySettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(proxySettingsPanelLayout.createSequentialGroup() + .addGroup(proxySettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(proxySettingsPanelLayout.createSequentialGroup() + .addGroup(proxySettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(proxyHTTPServerLabel) + .addComponent(proxyHTTPServer, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(proxySettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(proxyHTTPSServerLabel) + .addComponent(proxyHTTPSServer, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(proxySettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(proxyUser, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(proxyUserLabel))) + .addGroup(proxySettingsPanelLayout.createSequentialGroup() + .addGroup(proxySettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(proxyHTTPPortLabel) + .addComponent(proxyHTTPPort, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(proxySettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(proxyHTTPSPort, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(proxyHTTPSPortLabel)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(proxySettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(proxyPasswordLabel) + .addComponent(proxyPassword, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + + additionalBoardsManagerLabel.setText(_("Additional Boards Manager URLs: ")); + + extendedAdditionalUrlFieldWindow.setIcon(new ImageIcon(Base.getThemeImage("newwindow.gif", this))); + extendedAdditionalUrlFieldWindow.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + extendedAdditionalUrlFieldWindowActionPerformed(evt); + } + }); + + morePreferencesLabel.setForeground(Color.GRAY); + morePreferencesLabel.setText(_("More preferences can be edited directly in the file")); + + preferencesFileLabel.setText(PreferencesData.getPreferencesFile().getAbsolutePath()); + preferencesFileLabel.addMouseListener(new java.awt.event.MouseAdapter() { + public void mousePressed(java.awt.event.MouseEvent evt) { + preferencesFileLabelMousePressed(evt); + } + + public void mouseExited(java.awt.event.MouseEvent evt) { + preferencesFileLabelMouseExited(evt); + } + + public void mouseEntered(java.awt.event.MouseEvent evt) { + preferencesFileLabelMouseEntered(evt); + } + }); + + arduinoNotRunningLabel.setForeground(Color.GRAY); + arduinoNotRunningLabel.setText(_("(edit only when Arduino is not running)")); + + okButton.setText(I18n.PROMPT_OK); + okButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + okButtonActionPerformed(evt); + } + }); + + cancelButton.setText(I18n.PROMPT_CANCEL); + cancelButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + cancelButtonActionPerformed(evt); + } + }); + + checkboxesContainer.setLayout(new javax.swing.BoxLayout(checkboxesContainer, javax.swing.BoxLayout.Y_AXIS)); + + displayLineNumbersBox.setText(_("Display line numbers")); + checkboxesContainer.add(displayLineNumbersBox); + + enableCodeFoldingBox.setText(_("Enable Code Folding")); + checkboxesContainer.add(enableCodeFoldingBox); + + verifyUploadBox.setText(_("Verify code after upload")); + checkboxesContainer.add(verifyUploadBox); + + externalEditorBox.setText(_("Use external editor")); + checkboxesContainer.add(externalEditorBox); + + checkUpdatesBox.setText(_("Check for updates on startup")); + checkboxesContainer.add(checkUpdatesBox); + + updateExtensionBox.setText(_("Update sketch files to new extension on save (.pde -> .ino)")); + checkboxesContainer.add(updateExtensionBox); + + autoAssociateBox.setText(_("Automatically associate .ino files with Arduino")); + checkboxesContainer.add(autoAssociateBox); + + saveVerifyUploadBox.setText(_("Save when verifying or uploading")); + checkboxesContainer.add(saveVerifyUploadBox); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(proxySettingsPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addComponent(sketchbookLocationField) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(browseButton)) + .addComponent(checkboxesContainer, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(arduinoNotRunningLabel) + .addComponent(sketchbookLocationLabel) + .addGroup(layout.createSequentialGroup() + .addComponent(comboWarningsLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(comboWarnings, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(morePreferencesLabel) + .addGroup(layout.createSequentialGroup() + .addComponent(showVerboseLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(verboseCompilationBox) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(verboseUploadBox)) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(comboLanguageLabel) + .addComponent(fontSizeLabel)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(fontSizeField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(layout.createSequentialGroup() + .addComponent(comboLanguage, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(requiresRestartLabel)))) + .addComponent(preferencesFileLabel)) + .addGap(0, 0, Short.MAX_VALUE)) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addGap(0, 0, Short.MAX_VALUE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addComponent(additionalBoardsManagerLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(additionalBoardsManagerField, javax.swing.GroupLayout.PREFERRED_SIZE, 494, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(extendedAdditionalUrlFieldWindow, javax.swing.GroupLayout.PREFERRED_SIZE, 36, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addComponent(okButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(cancelButton))))) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addContainerGap() + .addComponent(sketchbookLocationLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(sketchbookLocationField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(browseButton)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(comboLanguageLabel) + .addComponent(comboLanguage, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(requiresRestartLabel)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(fontSizeLabel) + .addComponent(fontSizeField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(showVerboseLabel) + .addComponent(verboseCompilationBox) + .addComponent(verboseUploadBox)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(comboWarningsLabel) + .addComponent(comboWarnings, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(checkboxesContainer, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(proxySettingsPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(additionalBoardsManagerLabel) + .addComponent(additionalBoardsManagerField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(extendedAdditionalUrlFieldWindow, javax.swing.GroupLayout.PREFERRED_SIZE, 27, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(morePreferencesLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(preferencesFileLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(arduinoNotRunningLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(cancelButton) + .addComponent(okButton)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + + pack(); + }// //GEN-END:initComponents + + private void browseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseButtonActionPerformed + File dflt = new File(sketchbookLocationField.getText()); + File file = Base.selectFolder(_("Select new sketchbook location"), dflt, this); + if (file != null) { + String path = file.getAbsolutePath(); + if (Base.getPortableFolder() != null) { + path = FileUtils.relativePath(Base.getPortableFolder().toString(), path); + if (path == null) { + path = Base.getPortableSketchbookFolder(); + } + } + sketchbookLocationField.setText(path); + } + }//GEN-LAST:event_browseButtonActionPerformed + + private void extendedAdditionalUrlFieldWindowActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_extendedAdditionalUrlFieldWindowActionPerformed + final AdditionalBoardsManagerURLTextArea additionalBoardsManagerURLTextArea = new AdditionalBoardsManagerURLTextArea(this); + additionalBoardsManagerURLTextArea.setText(additionalBoardsManagerField.getText()); + additionalBoardsManagerURLTextArea.onOk(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + additionalBoardsManagerField.setText(additionalBoardsManagerURLTextArea.getText()); + } + }); + additionalBoardsManagerURLTextArea.setVisible(true); + }//GEN-LAST:event_extendedAdditionalUrlFieldWindowActionPerformed + + private void preferencesFileLabelMouseEntered(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_preferencesFileLabelMouseEntered + preferencesFileLabel.setForeground(new Color(0, 0, 140)); + }//GEN-LAST:event_preferencesFileLabelMouseEntered + + private void preferencesFileLabelMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_preferencesFileLabelMousePressed + Base.openFolder(PreferencesData.getPreferencesFile().getParentFile()); + }//GEN-LAST:event_preferencesFileLabelMousePressed + + private void preferencesFileLabelMouseExited(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_preferencesFileLabelMouseExited + preferencesFileLabel.setForeground(Color.BLACK); + }//GEN-LAST:event_preferencesFileLabelMouseExited + + private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed + dispatchEvent(new WindowEvent(this, WindowEvent.WINDOW_CLOSING)); + }//GEN-LAST:event_cancelButtonActionPerformed + + private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed + savePreferencesData(); + for (Editor editor : base.getEditors()) { + editor.applyPreferences(); + } + cancelButtonActionPerformed(evt); + }//GEN-LAST:event_okButtonActionPerformed + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JTextField additionalBoardsManagerField; + private javax.swing.JCheckBox autoAssociateBox; + private javax.swing.JCheckBox checkUpdatesBox; + private javax.swing.JComboBox comboLanguage; + private javax.swing.JComboBox comboWarnings; + private javax.swing.JCheckBox displayLineNumbersBox; + private javax.swing.JCheckBox enableCodeFoldingBox; + private javax.swing.JCheckBox externalEditorBox; + private javax.swing.JTextField fontSizeField; + private javax.swing.JLabel preferencesFileLabel; + private javax.swing.JTextField proxyHTTPPort; + private javax.swing.JTextField proxyHTTPSPort; + private javax.swing.JTextField proxyHTTPSServer; + private javax.swing.JTextField proxyHTTPServer; + private javax.swing.JPasswordField proxyPassword; + private javax.swing.JTextField proxyUser; + private javax.swing.JCheckBox saveVerifyUploadBox; + private javax.swing.JTextField sketchbookLocationField; + private javax.swing.JCheckBox updateExtensionBox; + private javax.swing.JCheckBox verboseCompilationBox; + private javax.swing.JCheckBox verboseUploadBox; + private javax.swing.JCheckBox verifyUploadBox; + // End of variables declaration//GEN-END:variables + + private void savePreferencesData() { + String oldPath = PreferencesData.get("sketchbook.path"); + String newPath = sketchbookLocationField.getText(); + if (newPath.isEmpty()) { + if (base.getPortableFolder() == null) { + newPath = base.getDefaultSketchbookFolderOrPromptForIt().toString(); + } else { + newPath = base.getPortableSketchbookFolder(); + } + } + if (!newPath.equals(oldPath)) { + base.rebuildSketchbookMenus(); + PreferencesData.set("sketchbook.path", newPath); + } + + Language newLanguage = (Language) comboLanguage.getSelectedItem(); + PreferencesData.set("editor.languages.current", newLanguage.getIsoCode()); + + String newSizeText = fontSizeField.getText(); + try { + int newSize = Integer.parseInt(newSizeText.trim()); + String pieces[] = PApplet.split(PreferencesData.get("editor.font"), ','); + pieces[2] = String.valueOf(newSize); + PreferencesData.set("editor.font", PApplet.join(pieces, ',')); + + } catch (Exception e) { + System.err.println(I18n.format(_("ignoring invalid font size {0}"), newSizeText)); + } + + // put each of the settings into the table + PreferencesData.setBoolean("build.verbose", verboseCompilationBox.isSelected()); + PreferencesData.setBoolean("upload.verbose", verboseUploadBox.isSelected()); + + WarningItem warningItem = (WarningItem) comboWarnings.getSelectedItem(); + PreferencesData.set("compiler.warning_level", warningItem.getValue()); + + PreferencesData.setBoolean("editor.linenumbers", displayLineNumbersBox.isSelected()); + + PreferencesData.setBoolean("editor.code_folding", enableCodeFoldingBox.isSelected()); + + PreferencesData.setBoolean("upload.verify", verifyUploadBox.isSelected()); + + PreferencesData.setBoolean("editor.save_on_verify", saveVerifyUploadBox.isSelected()); + + PreferencesData.setBoolean("editor.external", externalEditorBox.isSelected()); + + PreferencesData.setBoolean("update.check", checkUpdatesBox.isSelected()); + + PreferencesData.setBoolean("editor.update_extension", updateExtensionBox.isSelected()); + + if (autoAssociateBox != null) { + PreferencesData.setBoolean("platform.auto_file_type_associations", autoAssociateBox.isSelected()); + } + + PreferencesData.setBoolean("editor.save_on_verify", saveVerifyUploadBox.isSelected()); + + PreferencesData.set("proxy.http.server", proxyHTTPServer.getText()); + try { + PreferencesData.set("proxy.http.port", Integer.valueOf(proxyHTTPPort.getText()).toString()); + } catch (NumberFormatException e) { + PreferencesData.remove("proxy.http.port"); + } + PreferencesData.set("proxy.https.server", proxyHTTPSServer.getText()); + try { + PreferencesData.set("proxy.https.port", Integer.valueOf(proxyHTTPSPort.getText()).toString()); + } catch (NumberFormatException e) { + PreferencesData.remove("proxy.https.port"); + } + PreferencesData.set("proxy.user", proxyUser.getText()); + PreferencesData.set("proxy.password", new String(proxyPassword.getPassword())); + + PreferencesData.set("boardsmanager.additional.urls", additionalBoardsManagerField.getText().replace("\r\n", "\n").replace("\r", "\n").replace("\n", ",")); + + //editor.applyPreferences(); + } + + private void showPrerefencesData() { + sketchbookLocationField.setText(PreferencesData.get("sketchbook.path")); + + String currentLanguageISOCode = PreferencesData.get("editor.languages.current"); + for (Language language : languages) { + if (language.getIsoCode().equals(currentLanguageISOCode)) { + comboLanguage.setSelectedItem(language); + } + } + + Font editorFont = PreferencesData.getFont("editor.font"); + fontSizeField.setText(String.valueOf(editorFont.getSize())); + + verboseCompilationBox.setSelected(PreferencesData.getBoolean("build.verbose")); + verboseUploadBox.setSelected(PreferencesData.getBoolean("upload.verbose")); + + String currentWarningLevel = PreferencesData.get("compiler.warning_level", "none"); + for (WarningItem item : warningItems) { + if (currentWarningLevel.equals(item.getValue())) { + comboWarnings.setSelectedItem(item); + } + } + + displayLineNumbersBox.setSelected(PreferencesData.getBoolean("editor.linenumbers")); + + enableCodeFoldingBox.setSelected(PreferencesData.getBoolean("editor.code_folding")); + + verifyUploadBox.setSelected(PreferencesData.getBoolean("upload.verify")); + + externalEditorBox.setSelected(PreferencesData.getBoolean("editor.external")); + + checkUpdatesBox.setSelected(PreferencesData.getBoolean("update.check")); + + updateExtensionBox.setSelected(PreferencesData.get("editor.update_extension") == null || PreferencesData.getBoolean("editor.update_extension")); + + if (autoAssociateBox != null) { + autoAssociateBox.setSelected(PreferencesData.getBoolean("platform.auto_file_type_associations")); + } + + saveVerifyUploadBox.setSelected(PreferencesData.getBoolean("editor.save_on_verify")); + + proxyHTTPServer.setText(PreferencesData.get("proxy.http.server")); + try { + proxyHTTPPort.setText(Integer.toString(PreferencesData.getInteger("proxy.http.port", 8080))); + } catch (NumberFormatException e) { + proxyHTTPPort.setText(""); + } + proxyHTTPSServer.setText(PreferencesData.get("proxy.https.server")); + try { + proxyHTTPSPort.setText(Integer.toString(PreferencesData.getInteger("proxy.https.port", 8443))); + } catch (NumberFormatException e) { + proxyHTTPSPort.setText(""); + } + proxyUser.setText(PreferencesData.get("proxy.user")); + proxyPassword.setText(PreferencesData.get("proxy.password")); + + additionalBoardsManagerField.setText(PreferencesData.get("boardsmanager.additional.urls")); + } +} diff --git a/app/src/processing/app/AbstractMonitor.java b/app/src/processing/app/AbstractMonitor.java index 03a438f5d..d3ca60ad8 100644 --- a/app/src/processing/app/AbstractMonitor.java +++ b/app/src/processing/app/AbstractMonitor.java @@ -78,7 +78,7 @@ public abstract class AbstractMonitor extends JFrame implements ActionListener { getContentPane().setLayout(new BorderLayout()); Font consoleFont = Theme.getFont("console.font"); - Font editorFont = Preferences.getFont("editor.font"); + Font editorFont = PreferencesData.getFont("editor.font"); Font font = new Font(consoleFont.getName(), consoleFont.getStyle(), editorFont.getSize()); textArea = new TextAreaFIFO(8000000); @@ -124,12 +124,12 @@ public abstract class AbstractMonitor extends JFrame implements ActionListener { lineEndings = new JComboBox(new String[]{_("No line ending"), _("Newline"), _("Carriage return"), _("Both NL & CR")}); lineEndings.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { - Preferences.setInteger("serial.line_ending", lineEndings.getSelectedIndex()); + PreferencesData.setInteger("serial.line_ending", lineEndings.getSelectedIndex()); noLineEndingAlert.setForeground(pane.getBackground()); } }); - if (Preferences.get("serial.line_ending") != null) { - lineEndings.setSelectedIndex(Preferences.getInteger("serial.line_ending")); + if (PreferencesData.get("serial.line_ending") != null) { + lineEndings.setSelectedIndex(PreferencesData.getInteger("serial.line_ending")); } lineEndings.setMaximumSize(lineEndings.getMinimumSize()); @@ -160,13 +160,13 @@ public abstract class AbstractMonitor extends JFrame implements ActionListener { pack(); Dimension screen = Toolkit.getDefaultToolkit().getScreenSize(); - if (Preferences.get("last.screen.height") != null) { + if (PreferencesData.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"); + int screenW = PreferencesData.getInteger("last.screen.width"); + int screenH = PreferencesData.getInteger("last.screen.height"); if ((screen.width == screenW) && (screen.height == screenH)) { - String locationStr = Preferences.get("last.serial.location"); + String locationStr = PreferencesData.get("last.serial.location"); if (locationStr != null) { int[] location = PApplet.parseInt(PApplet.split(locationStr, ',')); setPlacement(location); diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index d844b4c36..41e53169d 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -22,7 +22,26 @@ package processing.app; +import cc.arduino.contributions.BuiltInCoreIsNewerCheck; +import cc.arduino.contributions.DownloadableContributionVersionComparator; +import cc.arduino.contributions.VersionHelper; +import cc.arduino.contributions.libraries.ContributedLibrary; +import cc.arduino.contributions.libraries.LibrariesIndexer; +import cc.arduino.contributions.libraries.LibraryInstaller; +import cc.arduino.contributions.libraries.ui.LibraryManagerUI; +import cc.arduino.contributions.packages.ContributedPlatform; +import cc.arduino.contributions.packages.ContributionInstaller; +import cc.arduino.contributions.packages.ContributionsIndexer; +import cc.arduino.contributions.packages.ui.ContributionManagerUI; +import cc.arduino.files.DeleteFilesOnShutdown; import cc.arduino.packages.DiscoveryManager; +import cc.arduino.utils.Progress; +import cc.arduino.view.*; +import cc.arduino.view.Event; +import com.google.common.base.Predicate; +import com.google.common.base.Predicates; +import com.google.common.collect.Collections2; +import org.apache.commons.lang3.StringUtils; import processing.app.debug.TargetBoard; import processing.app.debug.TargetPackage; import processing.app.debug.TargetPlatform; @@ -32,17 +51,23 @@ import processing.app.helpers.filefilters.OnlyFilesWithExtension; import processing.app.javax.swing.filechooser.FileNameExtensionFilter; import processing.app.legacy.PApplet; import processing.app.macosx.ThinkDifferent; -import processing.app.packages.Library; import processing.app.packages.LibraryList; +import processing.app.packages.UserLibrary; +import processing.app.syntax.PdeKeywords; +import processing.app.syntax.SketchTextAreaDefaultInputMap; import processing.app.tools.MenuScroller; import processing.app.tools.ZipDeflater; import javax.swing.*; + import java.awt.*; import java.awt.event.*; import java.io.*; import java.util.*; import java.util.List; +import java.util.logging.Handler; +import java.util.logging.Level; +import java.util.logging.Logger; import static processing.app.I18n._; @@ -55,10 +80,17 @@ import static processing.app.I18n._; */ public class Base { - static private boolean commandLine; + public static final Predicate CONTRIBUTED = new Predicate() { + @Override + public boolean apply(UserLibrary library) { + return library.getTypes() == null || library.getTypes().isEmpty() || library.getTypes().contains("Contributed"); + } + }; - // A single instance of the preferences window - Preferences preferencesFrame; + private static boolean commandLine; + public static volatile Base INSTANCE; + + public static SplashScreenHelper splashScreenHelper = new SplashScreenHelper(SplashScreen.getSplashScreen()); // set to true after the first time the menu is built. // so that the errors while building don't show up again. @@ -72,19 +104,45 @@ public class Base { // Location for untitled items static File untitledFolder; - // Current directory to use for relative paths specified on the - // commandline - static String currentDirectory = BaseNoGui.currentDirectory; - // p5 icon for the window // static Image icon; -// int editorCount; + // int editorCount; List editors = Collections.synchronizedList(new ArrayList()); Editor activeEditor; + // these menus are shared so that the board and serial port selections + // are the same for all windows (since the board and serial port that are + // actually used are determined by the preferences, which are shared) + private List boardsCustomMenus; + private volatile Action openBoardsManager; + + private final PdeKeywords pdeKeywords; + static public void main(String args[]) throws Exception { + System.setProperty("awt.useSystemAAFontSettings", "on"); + System.setProperty("swing.aatext", "true"); + + splashScreenHelper.splashText(_("Loading configuration...")); + + if (OSUtils.isMacOS()) { + ThinkDifferent.init(); + } + + try { + guardedMain(args); + } catch (Throwable e) { + e.printStackTrace(System.err); + System.exit(255); + } + } + + static public void guardedMain(String args[]) throws Exception { + Runtime.getRuntime().addShutdownHook(new Thread(DeleteFilesOnShutdown.INSTANCE)); + BaseNoGui.initLogger(); + + initLogger(); BaseNoGui.notifier = new GUIUserNotifier(); @@ -93,7 +151,9 @@ public class Base { BaseNoGui.initPortableFolder(); BaseNoGui.initParameters(args); - + + System.setProperty("swing.aatext", PreferencesData.get("editor.antialias", "true")); + BaseNoGui.initVersion(); // if (System.getProperty("mrj.version") != null) { @@ -157,9 +217,37 @@ public class Base { // Create a location for untitled sketches untitledFolder = createTempFolder("untitled"); - untitledFolder.deleteOnExit(); + DeleteFilesOnShutdown.add(untitledFolder); - new Base(args); + INSTANCE = new Base(args); + } + + + static public void initLogger() { + Handler consoleHandler = new ConsoleLogger(); + consoleHandler.setLevel(Level.ALL); + consoleHandler.setFormatter(new LogFormatter("%1$tl:%1$tM:%1$tS [%4$7s] %2$s: %5$s%n")); + + Logger globalLogger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME); + globalLogger.setLevel(consoleHandler.getLevel()); + + // Remove default + Handler[] handlers = globalLogger.getHandlers(); + for(Handler handler : handlers) { + globalLogger.removeHandler(handler); + } + Logger root = Logger.getLogger(""); + handlers = root.getHandlers(); + for(Handler handler : handlers) { + root.removeHandler(handler); + } + + globalLogger.addHandler(consoleHandler); + + Logger.getLogger("cc.arduino.packages.autocomplete").setParent(globalLogger); + Logger.getLogger("br.com.criativasoft.cpluslibparser").setParent(globalLogger); + Logger.getLogger(Base.class.getPackage().getName()).setParent(globalLogger); + } @@ -183,9 +271,9 @@ public class Base { Class.forName("com.sun.jdi.VirtualMachine"); } catch (ClassNotFoundException cnfe) { showError(_("Please install JDK 1.5 or later"), - _("Arduino 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); + _("Arduino 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); } } @@ -199,8 +287,6 @@ public class Base { public Base(String[] args) throws Exception { getPlatform().init(); - if (OSUtils.isMacOS()) - ThinkDifferent.init(this); String sketchbookPath = BaseNoGui.getSketchbookPath(); @@ -208,22 +294,28 @@ public class Base { if (sketchbookPath == null) { File defaultFolder = getDefaultSketchbookFolderOrPromptForIt(); if (BaseNoGui.getPortableFolder() != null) - Preferences.set("sketchbook.path", BaseNoGui.getPortableSketchbookFolder()); + PreferencesData.set("sketchbook.path", BaseNoGui.getPortableSketchbookFolder()); else - Preferences.set("sketchbook.path", defaultFolder.getAbsolutePath()); + PreferencesData.set("sketchbook.path", defaultFolder.getAbsolutePath()); if (!defaultFolder.exists()) { defaultFolder.mkdirs(); } } + splashScreenHelper.splashText(_("Initializing packages...")); BaseNoGui.initPackages(); - + splashScreenHelper.splashText(_("Preparing boards...")); + rebuildBoardsMenu(); + // Setup board-dependent variables. onBoardOrPortChange(); + this.pdeKeywords = new PdeKeywords(); + this.pdeKeywords.reload(); + CommandlineParser parser = CommandlineParser.newCommandlineParser(args); - for (String path: parser.getFilenames()) { + for (String path : parser.getFilenames()) { // Correctly resolve relative paths File file = absoluteFile(path); @@ -241,7 +333,7 @@ public class Base { boolean showEditor = parser.isGuiMode(); if (!parser.isForceSavePrefs()) - Preferences.setDoSave(showEditor); + PreferencesData.setDoSave(showEditor); if (handleOpen(file, nextEditorLocation(), showEditor) == null) { String mess = I18n.format(_("Failed to open sketch: \"{0}\""), path); // Open failure is fatal in upload/verify mode @@ -255,62 +347,166 @@ public class Base { // Save the preferences. For GUI mode, this happens in the quit // handler, but for other modes we should also make sure to save // them. - Preferences.save(); + PreferencesData.save(); - if (parser.isVerifyOrUploadMode()) { - // Set verbosity for command line build - Preferences.set("build.verbose", "" + parser.isDoVerboseBuild()); - Preferences.set("upload.verbose", "" + parser.isDoVerboseUpload()); + if (parser.isInstallBoard()) { + ContributionsIndexer indexer = new ContributionsIndexer(BaseNoGui.getSettingsFolder()); + ContributionInstaller installer = new ContributionInstaller(indexer) { + private String lastStatus = ""; - // Make sure these verbosity preferences are only for the - // current session - Preferences.setDoSave(false); - - Editor editor = editors.get(0); - - if (parser.isUploadMode()) { - // Build and upload - editor.exportHandler.run(); - } else { - // Build only - editor.runHandler.run(); + @Override + protected void onProgress(Progress progress) { + if (!lastStatus.equals(progress.getStatus())) { + System.out.println(progress.getStatus()); + } + lastStatus = progress.getStatus(); } + }; + List downloadedPackageIndexFiles = installer.updateIndex(); + installer.deleteUnknownFiles(downloadedPackageIndexFiles); + indexer.parseIndex(); + indexer.syncWithFilesystem(getHardwareFolder()); - // Error during build or upload - int res = editor.status.mode; - if (res == EditorStatus.ERR) + String[] boardToInstallParts = parser.getBoardToInstall().split(":"); + + ContributedPlatform selected = null; + if (boardToInstallParts.length == 3) { + selected = indexer.getIndex().findPlatform(boardToInstallParts[0], boardToInstallParts[1], VersionHelper.valueOf(boardToInstallParts[2]).toString()); + } else if (boardToInstallParts.length == 2) { + List platformsByName = indexer.getIndex().findPlatforms(boardToInstallParts[0], boardToInstallParts[1]); + Collections.sort(platformsByName, new DownloadableContributionVersionComparator()); + if (!platformsByName.isEmpty()) { + selected = platformsByName.get(platformsByName.size() - 1); + } + } + if (selected == null) { + System.out.println(_("Selected board is not available")); + System.exit(1); + } + + ContributedPlatform installed = indexer.getInstalled(boardToInstallParts[0], boardToInstallParts[1]); + + if (!selected.isReadOnly()) { + installer.install(selected); + } + + if (installed != null && !installed.isReadOnly()) { + installer.remove(installed); + } + + System.exit(0); + + } else if (parser.isInstallLibrary()) { + LibrariesIndexer indexer = new LibrariesIndexer(BaseNoGui.getSettingsFolder()); + LibraryInstaller installer = new LibraryInstaller(indexer) { + private String lastStatus = ""; + + @Override + protected void onProgress(Progress progress) { + if (!lastStatus.equals(progress.getStatus())) { + System.out.println(progress.getStatus()); + } + lastStatus = progress.getStatus(); + } + }; + indexer.parseIndex(); + BaseNoGui.onBoardOrPortChange(); + indexer.setSketchbookLibrariesFolder(BaseNoGui.getSketchbookLibrariesFolder()); + indexer.setLibrariesFolders(BaseNoGui.getLibrariesPath()); + installer.updateIndex(); + + for (String library : parser.getLibraryToInstall().split(",")) { + String[] libraryToInstallParts = library.split(":"); + + ContributedLibrary selected = null; + if (libraryToInstallParts.length == 2) { + selected = indexer.getIndex().find(libraryToInstallParts[0], VersionHelper.valueOf(libraryToInstallParts[1]).toString()); + } else if (libraryToInstallParts.length == 1) { + List librariesByName = indexer.getIndex().find(libraryToInstallParts[0]); + Collections.sort(librariesByName, new DownloadableContributionVersionComparator()); + if (!librariesByName.isEmpty()) { + selected = librariesByName.get(librariesByName.size() - 1); + } + } + if (selected == null) { + System.out.println(_("Selected library is not available")); System.exit(1); - - // No errors exit gracefully - System.exit(0); - } - else if (parser.isGuiMode()) { - // Check if there were previously opened sketches to be restored - restoreSketches(); - - // Create a new empty window (will be replaced with any files to be opened) - if (editors.isEmpty()) { - handleNew(); } - // Check for updates - if (Preferences.getBoolean("update.check")) { - new UpdateCheck(this); - } - } - else if (parser.isNoOpMode()) { - // Do nothing (intended for only changing preferences) - System.exit(0); - } - else if (parser.isGetPrefMode()) { - String value = Preferences.get(parser.getGetPref(), null); - if (value != null) { - System.out.println(value); - System.exit(0); + ContributedLibrary installed = indexer.getIndex().getInstalled(libraryToInstallParts[0]); + if (selected.isReadOnly()) { + installer.remove(installed); } else { - System.exit(4); + installer.install(selected, installed); } } + + System.exit(0); + + } else if (parser.isVerifyOrUploadMode()) { + splashScreenHelper.close(); + // Set verbosity for command line build + PreferencesData.set("build.verbose", "" + parser.isDoVerboseBuild()); + PreferencesData.set("upload.verbose", "" + parser.isDoVerboseUpload()); + PreferencesData.set("runtime.preserve.temp.files", Boolean.toString(parser.isPreserveTempFiles())); + + // Make sure these verbosity preferences are only for the + // current session + PreferencesData.setDoSave(false); + + Editor editor = editors.get(0); + + if (parser.isUploadMode()) { + splashScreenHelper.splashText(_("Verifying and uploading...")); + editor.exportHandler.run(); + } else { + splashScreenHelper.splashText(_("Verifying...")); + editor.runHandler.run(); + } + + // Error during build or upload + int res = editor.status.mode; + if (res == EditorStatus.ERR) + System.exit(1); + + // No errors exit gracefully + System.exit(0); + } else if (parser.isGuiMode()) { + splashScreenHelper.splashText(_("Starting...")); + + installKeyboardInputMap(); + + // Check if there were previously opened sketches to be restored + restoreSketches(); + + // Create a new empty window (will be replaced with any files to be opened) + if (editors.isEmpty()) { + handleNew(); + } + + // Check for updates + if (PreferencesData.getBoolean("update.check")) { + new UpdateCheck(this); + } + + new Thread(new BuiltInCoreIsNewerCheck(this)).start(); + + } else if (parser.isNoOpMode()) { + // Do nothing (intended for only changing preferences) + System.exit(0); + } else if (parser.isGetPrefMode()) { + String value = PreferencesData.get(parser.getGetPref(), null); + if (value != null) { + System.out.println(value); + System.exit(0); + } else { + System.exit(4); + } + } + } + + private void installKeyboardInputMap() { + UIManager.put("RSyntaxTextAreaUI.inputMap", new SketchTextAreaDefaultInputMap()); } /** @@ -318,7 +514,8 @@ public class Base { * sketch that was used (if any), and restores other Editor settings. * The complement to "storePreferences", this is called when the * application is first launched. - * @throws Exception + * + * @throws Exception */ protected boolean restoreSketches() throws Exception { // figure out window placement @@ -326,11 +523,11 @@ public class Base { Dimension screen = Toolkit.getDefaultToolkit().getScreenSize(); boolean windowPositionValid = true; - if (Preferences.get("last.screen.height") != null) { + if (PreferencesData.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"); + int screenW = PreferencesData.getInteger("last.screen.width"); + int screenH = PreferencesData.getInteger("last.screen.height"); if ((screen.width != screenW) || (screen.height != screenH)) { windowPositionValid = false; @@ -351,10 +548,10 @@ public class Base { // 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 count = PreferencesData.getInteger("last.sketch.count"); int opened = 0; for (int i = 0; i < count; i++) { - String path = Preferences.get("last.sketch" + i + ".path"); + String path = PreferencesData.get("last.sketch" + i + ".path"); if (BaseNoGui.getPortableFolder() != null) { File absolute = new File(BaseNoGui.getPortableFolder(), path); try { @@ -365,7 +562,7 @@ public class Base { } int[] location; if (windowPositionValid) { - String locationStr = Preferences.get("last.sketch" + i + ".location"); + String locationStr = PreferencesData.get("last.sketch" + i + ".location"); location = PApplet.parseInt(PApplet.split(locationStr, ',')); } else { location = nextEditorLocation(); @@ -386,8 +583,8 @@ public class Base { 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); + PreferencesData.setInteger("last.screen.width", screen.width); + PreferencesData.setInteger("last.screen.height", screen.height); String untitledPath = untitledFolder.getAbsolutePath(); @@ -398,7 +595,7 @@ public class Base { // 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()) { + !editor.getSketch().isModified()) { continue; } if (BaseNoGui.getPortableFolder() != null) { @@ -406,14 +603,14 @@ public class Base { if (path == null) continue; } - Preferences.set("last.sketch" + index + ".path", path); + PreferencesData.set("last.sketch" + index + ".path", path); int[] location = editor.getPlacement(); String locationStr = PApplet.join(PApplet.str(location), ","); - Preferences.set("last.sketch" + index + ".location", locationStr); + PreferencesData.set("last.sketch" + index + ".location", locationStr); index++; } - Preferences.setInteger("last.sketch.count", index); + PreferencesData.setInteger("last.sketch.count", index); } @@ -424,13 +621,12 @@ public class Base { String untitledPath = untitledFolder.getAbsolutePath(); if (path.startsWith(untitledPath)) { path = ""; - } else - if (BaseNoGui.getPortableFolder() != null) { + } else if (BaseNoGui.getPortableFolder() != null) { path = FileUtils.relativePath(BaseNoGui.getPortableFolder().toString(), path); if (path == null) path = ""; } - Preferences.set("last.sketch" + index + ".path", path); + PreferencesData.set("last.sketch" + index + ".path", path); } @@ -469,16 +665,16 @@ public class Base { protected int[] nextEditorLocation() { - int defaultWidth = Preferences.getInteger("editor.window.width.default"); - int defaultHeight = Preferences.getInteger("editor.window.height.default"); + int defaultWidth = PreferencesData.getInteger("editor.window.width.default"); + int defaultHeight = PreferencesData.getInteger("editor.window.height.default"); if (activeEditor == null) { Rectangle screen = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration().getBounds(); // If no current active editor, use default placement - return new int[] { - (screen.width - defaultWidth) / 2, - (screen.height - defaultHeight) / 2, - defaultWidth, defaultHeight, 0 + return new int[]{ + (screen.width - defaultWidth) / 2, + (screen.height - defaultHeight) / 2, + defaultWidth, defaultHeight, 0 }; } else { @@ -497,14 +693,14 @@ public class Base { location[1] += OVER; if (location[0] == OVER || - location[2] == OVER || - location[0] + location[2] > screen.width || - location[1] + location[3] > screen.height) { + 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 new int[]{ + (int) (Math.random() * (screen.width - defaultWidth)), + (int) (Math.random() * (screen.height - defaultHeight)), + defaultWidth, defaultHeight, 0 }; } @@ -519,14 +715,15 @@ public class Base { boolean breakTime = false; String[] months = { - "jan", "feb", "mar", "apr", "may", "jun", - "jul", "aug", "sep", "oct", "nov", "dec" + "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 shift whether shift is pressed, which will invert prompt setting * @param noPrompt disable prompt, no matter the setting */ protected File createNewUntitled() throws IOException { @@ -552,12 +749,12 @@ public class Base { // In 0159, avoid running past z by sending people outdoors. if (!breakTime) { 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); + _("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 { showWarning(_("Sunshine"), - _("No really, time for some fresh air for you."), null); + _("No really, time for some fresh air for you."), null); } return null; } @@ -582,7 +779,8 @@ public class Base { /** * Create a new untitled document in a new sketch window. - * @throws Exception + * + * @throws Exception */ public void handleNew() throws Exception { try { @@ -633,6 +831,7 @@ public class Base { /** * Open a sketch, replacing the sketch in the current window. + * * @param path Location of the primary pde file for the sketch. */ public void handleOpenReplace(File file) { @@ -652,12 +851,13 @@ public class Base { /** * Prompt for a sketch to open, and open it in a new window. - * @throws Exception + * + * @throws Exception */ public void handleOpenPrompt() throws Exception { // get the frontmost window frame for placing file dialog FileDialog fd = new FileDialog(activeEditor, _("Open an Arduino sketch..."), FileDialog.LOAD); - File lastFolder = new File(Preferences.get("last.folder", getSketchbookFolder().getAbsolutePath())); + File lastFolder = new File(PreferencesData.get("last.folder", getSketchbookFolder().getAbsolutePath())); if (lastFolder.exists() && lastFolder.isFile()) { lastFolder = lastFolder.getParentFile(); } @@ -681,17 +881,18 @@ public class Base { File inputFile = new File(directory, filename); - Preferences.set("last.folder", inputFile.getAbsolutePath()); + PreferencesData.set("last.folder", inputFile.getAbsolutePath()); handleOpen(inputFile); } /** * Open a sketch in a new window. + * * @param file File to open * @return the Editor object, so that properties (like 'untitled') - * can be set by the caller - * @throws Exception + * can be set by the caller + * @throws Exception */ public Editor handleOpen(File file) throws Exception { return handleOpen(file, nextEditorLocation(), true); @@ -777,6 +978,7 @@ public class Base { /** * 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. */ @@ -796,26 +998,26 @@ public class Base { // if (Preferences.getBoolean("sketchbook.closing_last_window_quits") || // (editor.untitled && !editor.getSketch().isModified())) { if (OSUtils.isMacOS()) { - Object[] options = { "OK", "Cancel" }; + Object[] options = {"OK", "Cancel"}; String prompt = - _(" " + - " " + - "Are you sure you want to Quit?" + - "

Closing the last open sketch will quit Arduino."); + _(" " + + " " + + "Are you sure you want to Quit?" + + "

Closing the last open sketch will quit Arduino."); int result = JOptionPane.showOptionDialog(editor, - prompt, - _("Quit"), - JOptionPane.YES_NO_OPTION, - JOptionPane.QUESTION_MESSAGE, - null, - options, - options[0]); + prompt, + _("Quit"), + JOptionPane.YES_NO_OPTION, + JOptionPane.QUESTION_MESSAGE, + null, + options, + options[0]); if (result == JOptionPane.NO_OPTION || - result == JOptionPane.CLOSED_OPTION) { + result == JOptionPane.CLOSED_OPTION) { return false; } } @@ -830,7 +1032,7 @@ public class Base { storeSketches(); // Save out the current prefs state - Preferences.save(); + PreferencesData.save(); // Since this wasn't an actual Quit event, call System.exit() System.exit(0); @@ -858,6 +1060,7 @@ public class Base { /** * Handler for File → Quit. + * * @return false if canceled, true otherwise. */ public boolean handleQuit() { @@ -876,7 +1079,7 @@ public class Base { editor.internalCloseRunner(); } // Save out the current prefs state - Preferences.save(); + PreferencesData.save(); if (!OSUtils.isMacOS()) { // If this was fired from the menu or an AppleEvent (the Finder), @@ -891,6 +1094,7 @@ public class Base { /** * Attempt to close each open sketch in preparation for quitting. + * * @return false if canceled along the way */ protected boolean handleQuitEach() { @@ -916,7 +1120,7 @@ public class Base { * 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() { + public void rebuildSketchbookMenus() { //System.out.println("async enter"); //new Exception().printStackTrace(); SwingUtilities.invokeLater(new Runnable() { @@ -938,14 +1142,14 @@ public class Base { // Add the single "Open" item item = Editor.newJMenuItem(_("Open..."), 'O'); item.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - try { - handleOpenPrompt(); - } catch (Exception e1) { - e1.printStackTrace(); - } + public void actionPerformed(ActionEvent e) { + try { + handleOpenPrompt(); + } catch (Exception e1) { + e1.printStackTrace(); } - }); + } + }); menu.add(item); menu.addSeparator(); @@ -971,7 +1175,7 @@ public class Base { //System.out.println("rebuilding sketchbook menu"); //new Exception().printStackTrace(); try { - menu.removeAll(); + menu.removeAll(); addSketches(menu, getSketchbookFolder(), false); //addSketches(menu, getSketchbookFolder()); } catch (IOException e) { @@ -980,15 +1184,15 @@ public class Base { } public LibraryList getIDELibs() { - if (getLibraries() == null) - return new LibraryList(); - LibraryList res = new LibraryList(getLibraries()); - res.removeAll(getUserLibs()); - return res; + LibraryList installedLibraries = new LibraryList(BaseNoGui.librariesIndexer.getInstalledLibraries()); + List libs = new LinkedList(Collections2.filter(new LinkedList(installedLibraries), Predicates.not(CONTRIBUTED))); + return new LibraryList(libs); } public LibraryList getUserLibs() { - return BaseNoGui.getUserLibs(); + LibraryList installedLibraries = new LibraryList(BaseNoGui.librariesIndexer.getInstalledLibraries()); + List libs = new LinkedList(Collections2.filter(new LinkedList(installedLibraries), CONTRIBUTED)); + return new LibraryList(libs); } public void rebuildImportMenu(JMenu importMenu) { @@ -996,7 +1200,16 @@ public class Base { return; importMenu.removeAll(); - JMenuItem addLibraryMenuItem = new JMenuItem(_("Add Library...")); + JMenuItem menu = new JMenuItem(_("Manage Libraries...")); + menu.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + openManageLibrariesDialog(); + } + }); + importMenu.add(menu); + importMenu.addSeparator(); + + JMenuItem addLibraryMenuItem = new JMenuItem(_("Add .ZIP Library...")); addLibraryMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { Base.this.handleAddLibrary(); @@ -1007,31 +1220,34 @@ public class Base { }); importMenu.add(addLibraryMenuItem); importMenu.addSeparator(); - + // Split between user supplied libraries and IDE libraries TargetPlatform targetPlatform = getTargetPlatform(); - + if (targetPlatform != null) { LibraryList ideLibs = getIDELibs(); LibraryList userLibs = getUserLibs(); try { // Find the current target. Get the platform, and then select the // correct name and core path. - PreferencesMap prefs = targetPlatform.getPreferences(); - if (prefs != null) { - String platformName = prefs.get("name"); - if (platformName != null) { - JMenuItem platformItem = new JMenuItem(_(platformName)); - platformItem.setEnabled(false); - importMenu.add(platformItem); - } - } + String platformNameLabel; + platformNameLabel = StringUtils.capitalize(targetPlatform.getContainerPackage().getId()) + "/" + StringUtils.capitalize(targetPlatform.getId()); + platformNameLabel = I18n.format(_("{0} libraries"), platformNameLabel); + JMenuItem platformItem = new JMenuItem(_(platformNameLabel)); + platformItem.setEnabled(false); + importMenu.add(platformItem); + if (ideLibs.size() > 0) { - importMenu.addSeparator(); addLibraries(importMenu, ideLibs); } + if (userLibs.size() > 0) { - importMenu.addSeparator(); + if (ideLibs.size() > 0) { + importMenu.addSeparator(); + } + JMenuItem contributedLibraryItem = new JMenuItem(_("Contributed libraries")); + contributedLibraryItem.setEnabled(false); + importMenu.add(contributedLibraryItem); addLibraries(importMenu, userLibs); } } catch (IOException e) { @@ -1053,14 +1269,14 @@ public class Base { // Add examples from libraries LibraryList ideLibs = getIDELibs(); ideLibs.sort(); - for (Library lib : ideLibs) + for (UserLibrary lib : ideLibs) addSketchesSubmenu(menu, lib, false); LibraryList userLibs = getUserLibs(); - if (userLibs.size()>0) { + if (userLibs.size() > 0) { menu.addSeparator(); userLibs.sort(); - for (Library lib : userLibs) + for (UserLibrary lib : userLibs) addSketchesSubmenu(menu, lib, false); } } catch (IOException e) { @@ -1068,14 +1284,6 @@ public class Base { } } - public LibraryList scanLibraries(List folders) throws IOException { - return BaseNoGui.scanLibraries(folders); - } - - public LibraryList scanLibraries(File folder) throws IOException { - return BaseNoGui.scanLibraries(folder); - } - public void onBoardOrPortChange() { BaseNoGui.onBoardOrPortChange(); @@ -1084,60 +1292,136 @@ public class Base { editor.onBoardOrPortChange(); } - public void rebuildBoardsMenu(JMenu toolsMenu, Editor editor) throws Exception { - // If there are no platforms installed skip menu creation + private void openManageLibrariesDialog() { + @SuppressWarnings("serial") + LibraryManagerUI managerUI = new LibraryManagerUI(activeEditor) { + @Override + protected void onIndexesUpdated() throws Exception { + BaseNoGui.initPackages(); + rebuildBoardsMenu(); + onBoardOrPortChange(); + setIndexer(BaseNoGui.librariesIndexer); + } + }; + managerUI.setLocationRelativeTo(activeEditor); + managerUI.setIndexer(BaseNoGui.librariesIndexer); + managerUI.setVisible(true); + // Manager dialog is modal, waits here until closed + + //handleAddLibrary(); + onBoardOrPortChange(); + rebuildImportMenu(Editor.importMenu); + rebuildExamplesMenu(Editor.examplesMenu); + } + + private void openInstallBoardDialog(final String filterText) throws Exception { + // Create dialog for contribution manager + @SuppressWarnings("serial") + ContributionManagerUI managerUI = new ContributionManagerUI(activeEditor) { + @Override + protected void onIndexesUpdated() throws Exception { + BaseNoGui.initPackages(); + rebuildBoardsMenu(); + setIndexer(BaseNoGui.indexer); + if (StringUtils.isNotEmpty(filterText)) { + setFilterText(filterText); + } + + } + }; + managerUI.setLocationRelativeTo(activeEditor); + managerUI.setIndexer(BaseNoGui.indexer); + managerUI.setVisible(true); + // Installer dialog is modal, waits here until closed + + // Reload all boards (that may have been installed/updated/removed) + BaseNoGui.initPackages(); + rebuildBoardsMenu(); + onBoardOrPortChange(); + } + + public void rebuildBoardsMenu() throws Exception { + boardsCustomMenus = new LinkedList(); + + // The first custom menu is the "Board" selection submenu + JMenu boardMenu = new JMenu(_("Board")); + boardMenu.putClientProperty("removeOnWindowDeactivation", true); + MenuScroller.setScrollerFor(boardMenu); + + openBoardsManager = new AbstractAction(_("Boards Manager...")) { + public void actionPerformed(ActionEvent actionevent) { + String filterText = ""; + if (actionevent instanceof cc.arduino.view.Event) { + filterText = ((Event) actionevent).getPayload().get("filterText").toString(); + } + try { + openInstallBoardDialog(filterText); + } catch (Exception e) { + //TODO show error + e.printStackTrace(); + } + } + }; + boardMenu.add(new JMenuItem(openBoardsManager)); + boardsCustomMenus.add(boardMenu); + + // If there are no platforms installed we are done if (BaseNoGui.packages.size() == 0) return; - JMenu boardsMenu = getBoardCustomMenu(); + // Separate "Install boards..." command from installed boards + boardMenu.add(new JSeparator()); - boolean first = true; + // Generate custom menus for all platforms + Set customMenusTitles = new HashSet(); + for (TargetPackage targetPackage : BaseNoGui.packages.values()) { + for (TargetPlatform targetPlatform : targetPackage.platforms()) { + customMenusTitles.addAll(targetPlatform.getCustomMenus().values()); + } + } + for (String customMenuTitle : customMenusTitles) { + JMenu customMenu = new JMenu(_(customMenuTitle)); + customMenu.putClientProperty("removeOnWindowDeactivation", true); + boardsCustomMenus.add(customMenu); + } List menuItemsToClickAfterStartup = new LinkedList(); ButtonGroup boardsButtonGroup = new ButtonGroup(); Map buttonGroupsMap = new HashMap(); - // Generate custom menus for all platforms - Set titles = new HashSet(); - for (TargetPackage targetPackage : BaseNoGui.packages.values()) { - for (TargetPlatform targetPlatform : targetPackage.platforms()) - titles.addAll(targetPlatform.getCustomMenus().values()); - } - for (String title : titles) - makeBoardCustomMenu(toolsMenu, _(title)); - // Cycle through all packages + boolean first = true; for (TargetPackage targetPackage : BaseNoGui.packages.values()) { // For every package cycle through all platform for (TargetPlatform targetPlatform : targetPackage.platforms()) { // Add a separator from the previous platform if (!first) - boardsMenu.add(new JSeparator()); + boardMenu.add(new JSeparator()); first = false; // Add a title for each platform - String platformLabel = targetPlatform.getPreferences().get("name"); + String platformLabel = targetPlatform.getPreferences().get("name"); if (platformLabel != null && !targetPlatform.getBoards().isEmpty()) { JMenuItem menuLabel = new JMenuItem(_(platformLabel)); menuLabel.setEnabled(false); - boardsMenu.add(menuLabel); + boardMenu.add(menuLabel); } // Cycle through all boards of this platform for (TargetBoard board : targetPlatform.getBoards().values()) { - JMenuItem item = createBoardMenusAndCustomMenus(menuItemsToClickAfterStartup, - buttonGroupsMap, - board, targetPlatform, targetPackage); - boardsMenu.add(item); + JMenuItem item = createBoardMenusAndCustomMenus(boardsCustomMenus, menuItemsToClickAfterStartup, + buttonGroupsMap, + board, targetPlatform, targetPackage); + boardMenu.add(item); boardsButtonGroup.add(item); } } } if (menuItemsToClickAfterStartup.isEmpty()) { - menuItemsToClickAfterStartup.add(selectFirstEnabledMenuItem(boardsMenu)); + menuItemsToClickAfterStartup.add(selectFirstEnabledMenuItem(boardMenu)); } for (JMenuItem menuItemToClick : menuItemsToClickAfterStartup) { @@ -1147,24 +1431,24 @@ public class Base { } private JRadioButtonMenuItem createBoardMenusAndCustomMenus( - List menuItemsToClickAfterStartup, + final List boardsCustomMenus, List menuItemsToClickAfterStartup, Map buttonGroupsMap, TargetBoard board, TargetPlatform targetPlatform, TargetPackage targetPackage) - throws Exception { - String selPackage = Preferences.get("target_package"); - String selPlatform = Preferences.get("target_platform"); - String selBoard = Preferences.get("board"); + throws Exception { + String selPackage = PreferencesData.get("target_package"); + String selPlatform = PreferencesData.get("target_platform"); + String selBoard = PreferencesData.get("board"); String boardId = board.getId(); String packageName = targetPackage.getId(); String platformName = targetPlatform.getId(); - + // Setup a menu item for the current board @SuppressWarnings("serial") Action action = new AbstractAction(board.getName()) { public void actionPerformed(ActionEvent actionevent) { - selectBoard((TargetBoard)getValue("b")); - filterVisibilityOfSubsequentBoardMenus((TargetBoard)getValue("b"), 1); + selectBoard((TargetBoard) getValue("b")); + filterVisibilityOfSubsequentBoardMenus(boardsCustomMenus, (TargetBoard) getValue("b"), 1); onBoardOrPortChange(); rebuildImportMenu(Editor.importMenu); @@ -1176,7 +1460,7 @@ public class Base { JRadioButtonMenuItem item = new JRadioButtonMenuItem(action); if (selBoard.equals(boardId) && selPackage.equals(packageName) - && selPlatform.equals(platformName)) { + && selPlatform.equals(platformName)) { menuItemsToClickAfterStartup.add(item); } @@ -1184,14 +1468,14 @@ public class Base { for (final String menuId : customMenus.keySet()) { String title = customMenus.get(menuId); JMenu menu = getBoardCustomMenu(_(title)); - + if (board.hasMenu(menuId)) { PreferencesMap boardCustomMenu = board.getMenuLabels(menuId); for (String customMenuOption : boardCustomMenu.keySet()) { @SuppressWarnings("serial") Action subAction = new AbstractAction(_(boardCustomMenu.get(customMenuOption))) { public void actionPerformed(ActionEvent e) { - Preferences.set("custom_" + menuId, ((TargetBoard)getValue("board")).getId() + "_" + getValue("custom_menu_option")); + PreferencesData.set("custom_" + menuId, ((TargetBoard) getValue("board")).getId() + "_" + getValue("custom_menu_option")); onBoardOrPortChange(); } }; @@ -1206,20 +1490,21 @@ public class Base { menu.add(subItem); buttonGroupsMap.get(menuId).add(subItem); - String selectedCustomMenuEntry = Preferences.get("custom_" + menuId); + String selectedCustomMenuEntry = PreferencesData.get("custom_" + menuId); if (selBoard.equals(boardId) && (boardId + "_" + customMenuOption).equals(selectedCustomMenuEntry)) { menuItemsToClickAfterStartup.add(subItem); } } } } - + return item; } - private static void filterVisibilityOfSubsequentBoardMenus(TargetBoard board, int fromIndex) { - for (int i = fromIndex; i < Editor.boardsMenus.size(); i++) { - JMenu menu = Editor.boardsMenus.get(i); + private void filterVisibilityOfSubsequentBoardMenus(List boardsCustomMenus, TargetBoard board, + int fromIndex) { + for (int i = fromIndex; i < boardsCustomMenus.size(); i++) { + JMenu menu = boardsCustomMenus.get(i); for (int m = 0; m < menu.getItemCount(); m++) { JMenuItem menuItem = menu.getItem(m); menuItem.setVisible(menuItem.getAction().getValue("board").equals(board)); @@ -1245,21 +1530,12 @@ public class Base { return false; } - private JMenu makeBoardCustomMenu(JMenu toolsMenu, String label) { - JMenu menu = new JMenu(label); - Editor.boardsMenus.add(menu); - toolsMenu.add(menu); - return menu; - } - - private JMenu getBoardCustomMenu() throws Exception { - return getBoardCustomMenu(_("Board")); - } - private JMenu getBoardCustomMenu(String label) throws Exception { - for (JMenu menu : Editor.boardsMenus) - if (label.equals(menu.getText())) + for (JMenu menu : boardsCustomMenus) { + if (label.equals(menu.getText())) { return menu; + } + } throw new Exception("Custom menu not found!"); } @@ -1285,7 +1561,7 @@ public class Base { } private static JMenuItem selectFirstEnabledMenuItem(JMenu menu) { - for (int i = 0; i < menu.getItemCount(); i++) { + for (int i = 1; i < menu.getItemCount(); i++) { JMenuItem item = menu.getItem(i); if (item != null && item.isEnabled()) { return item; @@ -1313,14 +1589,14 @@ public class Base { @SuppressWarnings("serial") AbstractAction action = new AbstractAction(targetPlatform - .getProgrammer(programmer).get("name")) { + .getProgrammer(programmer).get("name")) { public void actionPerformed(ActionEvent actionevent) { - Preferences.set("programmer", "" + getValue("id")); + PreferencesData.set("programmer", "" + getValue("id")); } }; action.putValue("id", id); JMenuItem item = new JRadioButtonMenuItem(action); - if (Preferences.get("programmer").equals(id)) + if (PreferencesData.get("programmer").equals(id)) item.setSelected(true); group.add(item); menu.add(item); @@ -1370,15 +1646,15 @@ public class Base { return ifound; } - private boolean addSketchesSubmenu(JMenu menu, Library lib, + private boolean addSketchesSubmenu(JMenu menu, UserLibrary lib, boolean replaceExisting) - throws IOException { - return addSketchesSubmenu(menu, lib.getName(), lib.getFolder(), - replaceExisting); + throws IOException { + return addSketchesSubmenu(menu, lib.getName(), lib.getInstalledFolder(), + replaceExisting); } private boolean addSketchesSubmenu(JMenu menu, String name, File folder, - final boolean replaceExisting) throws IOException { + final boolean replaceExisting) throws IOException { ActionListener listener = new ActionListener() { public void actionPerformed(ActionEvent e) { @@ -1400,7 +1676,7 @@ public class Base { } } else { showWarning(_("Sketch Does Not Exist"), - _("The selected sketch no longer exists.\n" + _("The selected sketch no longer exists.\n" + "You may need to restart Arduino to update\n" + "the sketchbook menu."), null); } @@ -1417,13 +1693,13 @@ public class Base { if (!BaseNoGui.isSanitaryName(name)) { if (!builtOnce) { String complaining = I18n - .format( - _("The sketch \"{0}\" 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" - + "{1}"), name, entry.getAbsolutePath()); + .format( + _("The sketch \"{0}\" 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" + + "{1}"), name, entry.getAbsolutePath()); showMessage(_("Ignoring sketch with bad name"), complaining); } return false; @@ -1455,11 +1731,11 @@ public class Base { LibraryList list = new LibraryList(libs); list.sort(); - for (Library lib : list) { + for (UserLibrary lib : list) { @SuppressWarnings("serial") AbstractAction action = new AbstractAction(lib.getName()) { public void actionPerformed(ActionEvent event) { - Library l = (Library) getValue("library"); + UserLibrary l = (UserLibrary) getValue("library"); try { activeEditor.getSketch().importLibrary(l); } catch (IOException e) { @@ -1504,29 +1780,30 @@ public class Base { */ @SuppressWarnings("serial") public void handleAbout() { - final Image image = getLibImage("about.jpg", activeEditor); + final Image image = getLibImage("about.png", activeEditor); final Window window = new Window(activeEditor) { - public void paint(Graphics g) { - g.drawImage(image, 0, 0, null); + 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); + 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(BaseNoGui.VERSION_NAME, 50, 30); - } - }; + g.setFont(new Font("SansSerif", Font.PLAIN, 11)); + g.setColor(Color.white); + g.drawString(BaseNoGui.VERSION_NAME_LONG, 33, 20); + } + }; window.addMouseListener(new MouseAdapter() { - public void mousePressed(MouseEvent e) { - window.dispose(); - } - }); + 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.setBounds((screen.width - w) / 2, (screen.height - h) / 2, w, h); + window.setLocationRelativeTo(activeEditor); window.setVisible(true); } @@ -1535,8 +1812,13 @@ public class Base { * Show the Preferences window. */ public void handlePrefs() { - if (preferencesFrame == null) preferencesFrame = new Preferences(); - preferencesFrame.showFrame(activeEditor); + cc.arduino.view.preferences.Preferences dialog = new cc.arduino.view.preferences.Preferences(activeEditor, this); + if (activeEditor != null) { + dialog.setLocationRelativeTo(activeEditor); + } + dialog.pack(); + dialog.setMinimumSize(dialog.getSize()); + dialog.setVisible(true); } @@ -1567,8 +1849,6 @@ public class Base { // return PConstants.OTHER; // } // } - - static public Platform getPlatform() { return BaseNoGui.getPlatform(); } @@ -1604,6 +1884,7 @@ public class Base { * 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 */ @@ -1629,8 +1910,9 @@ public class Base { } + // XXX: Remove this method and make librariesIndexer non-static static public LibraryList getLibraries() { - return BaseNoGui.getLibraries(); + return BaseNoGui.librariesIndexer.getInstalledLibraries(); } @@ -1660,7 +1942,7 @@ public class Base { //Get the core libraries static public File getCoreLibraries(String path) { - return getContentFile(path); + return getContentFile(path); } static public String getHardwarePath() { @@ -1711,6 +1993,10 @@ public class Base { return BaseNoGui.getBoardPreferences(); } + public List getBoardsCustomMenus() { + return boardsCustomMenus; + } + static public File getPortableFolder() { return BaseNoGui.getPortableFolder(); } @@ -1741,7 +2027,7 @@ public class Base { } - protected File getDefaultSketchbookFolderOrPromptForIt() { + public File getDefaultSketchbookFolderOrPromptForIt() { File sketchbookFolder = BaseNoGui.getDefaultSketchbookFolder(); @@ -1757,8 +2043,8 @@ public class Base { if (!result) { showError(_("You forgot your sketchbook"), - _("Arduino cannot run because it could not\n" + - "create a folder to store your sketchbook."), null); + _("Arduino cannot run because it could not\n" + + "create a folder to store your sketchbook."), null); } return sketchbookFolder; @@ -1802,13 +2088,14 @@ public class Base { } catch (Exception e) { showWarning(_("Problem Opening URL"), - I18n.format(_("Could not open the URL\n{0}"), url), e); + I18n.format(_("Could not open the URL\n{0}"), 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() { @@ -1826,7 +2113,7 @@ public class Base { } catch (Exception e) { showWarning(_("Problem Opening Folder"), - I18n.format(_("Could not open the folder\n{0}"), file.getAbsolutePath()), e); + I18n.format(_("Could not open the folder\n{0}"), file.getAbsolutePath()), e); } } @@ -1834,7 +2121,7 @@ public class Base { // ................................................................. - static public File selectFolder(String prompt, File folder, Frame frame) { + static public File selectFolder(String prompt, File folder, Component parent) { JFileChooser fc = new JFileChooser(); fc.setDialogTitle(prompt); if (folder != null) { @@ -1842,7 +2129,7 @@ public class Base { } fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); - int returned = fc.showOpenDialog(new JDialog()); + int returned = fc.showOpenDialog(parent); if (returned == JFileChooser.APPROVE_OPTION) { return fc.getSelectedFile(); } @@ -1860,6 +2147,14 @@ public class Base { // don't use the low-res icon on Mac OS X; the window should // already have the right icon from the .app file. if (OSUtils.isMacOS()) return; + + // don't use the low-res icon on Linux + if (OSUtils.isLinux()){ + String current = System.getProperty("user.dir"); + Image image = Toolkit.getDefaultToolkit().createImage(current + "/lib/arduino.png"); + frame.setIconImage(image); + return; + } Image image = Toolkit.getDefaultToolkit().createImage(PApplet.ICON_IMAGE); frame.setIconImage(image); @@ -1893,12 +2188,12 @@ public class Base { ActionListener disposer) { KeyStroke stroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0); root.registerKeyboardAction(disposer, stroke, - JComponent.WHEN_IN_FOCUSED_WINDOW); + JComponent.WHEN_IN_FOCUSED_WINDOW); int modifiers = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(); stroke = KeyStroke.getKeyStroke('W', modifiers); root.registerKeyboardAction(disposer, stroke, - JComponent.WHEN_IN_FOCUSED_WINDOW); + JComponent.WHEN_IN_FOCUSED_WINDOW); } @@ -1906,14 +2201,27 @@ public class Base { static public void showReference(String filename) { - File referenceFolder = getContentFile("reference/arduino.cc/en"); + showReference("reference/arduino.cc/en", filename); + } + + static public void showReference(String prefix, String filename) { + File referenceFolder = getContentFile(prefix); File referenceFile = new File(referenceFolder, filename); if (!referenceFile.exists()) referenceFile = new File(referenceFolder, filename + ".html"); - openURL(referenceFile.getAbsolutePath()); + + if(referenceFile.exists()){ + openURL(referenceFile.getAbsolutePath()); + }else{ + showWarning(_("Problem Opening URL"), I18n.format(_("Could not open the URL\n{0}"), referenceFile), null); + } } - static public void showGettingStarted() { + public static void showEdisonGettingStarted() { + showReference("reference/Edison_help_files", "ArduinoIDE_guide_edison"); + } + + static public void showArduinoGettingStarted() { if (OSUtils.isMacOS()) { showReference("Guide/MacOSX"); } else if (OSUtils.isWindows()) { @@ -1984,15 +2292,14 @@ public class Base { // ................................................................... - // incomplete static public int showYesNoCancelQuestion(Editor editor, String title, String primary, String secondary) { if (!OSUtils.isMacOS()) { int result = - JOptionPane.showConfirmDialog(null, primary + "\n" + secondary, title, - JOptionPane.YES_NO_CANCEL_OPTION, - JOptionPane.QUESTION_MESSAGE); + JOptionPane.showConfirmDialog(null, primary + "\n" + secondary, title, + JOptionPane.YES_NO_CANCEL_OPTION, + JOptionPane.QUESTION_MESSAGE); return result; // if (result == JOptionPane.YES_OPTION) { // @@ -2010,18 +2317,18 @@ public class Base { // 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); + 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" + String[] options = new String[]{ + "Save", "Cancel", "Don't Save" }; pane.setOptions(options); @@ -2031,7 +2338,7 @@ public class Base { // 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)); + new Integer(2)); JDialog dialog = pane.createDialog(editor, null); dialog.setVisible(true); @@ -2063,29 +2370,29 @@ public class Base { // } static public int showYesNoQuestion(Frame editor, String title, - String primary, String secondary) { + String primary, String secondary) { if (!OSUtils.isMacOS()) { return JOptionPane.showConfirmDialog(editor, - "" + - "" + primary + "" + - "
" + secondary, title, - JOptionPane.YES_NO_OPTION, - JOptionPane.QUESTION_MESSAGE); + "" + + "" + primary + "" + + "
" + secondary, title, + JOptionPane.YES_NO_OPTION, + JOptionPane.QUESTION_MESSAGE); } else { // Pane formatting adapted from the Quaqua guide // http://www.randelshofer.ch/quaqua/guide/joptionpane.html JOptionPane pane = - new JOptionPane(" " + - " " + - "" + primary + "" + - "

" + secondary + "

", - JOptionPane.QUESTION_MESSAGE); + new JOptionPane(" " + + " " + + "" + primary + "" + + "

" + secondary + "

", + JOptionPane.QUESTION_MESSAGE); - String[] options = new String[] { - "Yes", "No" + String[] options = new String[]{ + "Yes", "No" }; pane.setOptions(options); @@ -2143,7 +2450,6 @@ public class Base { return null; } */ - static public File getContentFile(String name) { return BaseNoGui.getContentFile(name); } @@ -2161,28 +2467,20 @@ public class Base { * 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()); + Image image = tk.getImage(imageLocation.getAbsolutePath()); MediaTracker tracker = new MediaTracker(who); tracker.addImage(image, 0); try { tracker.waitForAll(); - } catch (InterruptedException e) { } + } 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 BaseNoGui.getLibStream(filename); - } - - // ................................................................... @@ -2200,34 +2498,38 @@ public class Base { */ 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; + FileInputStream input = null; + try { + 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; + } + return buffer; + } finally { + if (input != null) { + input.close(); + } } - input.close(); // weren't properly being closed - input = null; - return buffer; } - /** * Read from a file with a bunch of attribute/value pairs * that are separated by = and ignore comments with #. */ - static public HashMap readSettings(File inputFile) { - HashMap outgoing = new HashMap(); + static public HashMap readSettings(File inputFile) { + HashMap outgoing = new HashMap(); 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(); + lines[i].trim() : lines[i].substring(0, hash).trim(); if (line.length() == 0) continue; int equals = line.indexOf('='); @@ -2246,20 +2548,25 @@ public class Base { 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); + InputStream from = null; + OutputStream to = null; + try { + from = new BufferedInputStream(new FileInputStream(sourceFile)); + 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(); + } finally { + if (from != null) { + from.close(); // ?? + } + if (to != null) { + to.close(); // ?? + } } - to.flush(); - from.close(); // ?? - from = null; - to.close(); // ?? - to = null; targetFile.setLastModified(sourceFile.lastModified()); } @@ -2340,7 +2647,7 @@ public class Base { for (int i = 0; i < files.length; i++) { if (files[i].equals(".") || (files[i].equals("..")) || - files[i].equals(".DS_Store")) continue; + files[i].equals(".DS_Store")) continue; File fella = new File(folder, files[i]); if (fella.isDirectory()) { size += calcFolderSize(fella); @@ -2434,9 +2741,9 @@ public class Base { String libName = libFolder.getName(); if (!BaseNoGui.isSanitaryName(libName)) { String mess = I18n.format(_("The library \"{0}\" 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)"), - libName); + + "Library names must contain only basic letters and numbers.\n" + + "(ASCII only and no spaces, and it cannot start with a number)"), + libName); activeEditor.statusError(mess); return; } @@ -2453,7 +2760,7 @@ public class Base { activeEditor.statusError(e); return; } - activeEditor.statusNotice(_("Library added to your libraries. Check \"Import library\" menu")); + activeEditor.statusNotice(_("Library added to your libraries. Check \"Include library\" menu")); } finally { // delete zip created temp folder, if exists FileUtils.recursiveDelete(tmpFolder); @@ -2463,4 +2770,24 @@ public class Base { public static DiscoveryManager getDiscoveryManager() { return BaseNoGui.getDiscoveryManager(); } + + public Editor getActiveEditor() { + return activeEditor; + } + + public boolean hasActiveEditor() { + return activeEditor != null; + } + + public List getEditors() { + return new LinkedList(editors); + } + + public Action getOpenBoardsManager() { + return openBoardsManager; + } + + public PdeKeywords getPdeKeywords() { + return pdeKeywords; + } } diff --git a/app/src/processing/app/CaretAwareUndoableEdit.java b/app/src/processing/app/CaretAwareUndoableEdit.java index ba8e67d85..b0983ad2f 100644 --- a/app/src/processing/app/CaretAwareUndoableEdit.java +++ b/app/src/processing/app/CaretAwareUndoableEdit.java @@ -1,6 +1,6 @@ package processing.app; -import processing.app.syntax.JEditTextArea; +import processing.app.syntax.SketchTextArea; import javax.swing.undo.CannotRedoException; import javax.swing.undo.CannotUndoException; @@ -11,7 +11,7 @@ public class CaretAwareUndoableEdit implements UndoableEdit { private final UndoableEdit undoableEdit; private final int caretPosition; - public CaretAwareUndoableEdit(UndoableEdit undoableEdit, JEditTextArea textArea) { + public CaretAwareUndoableEdit(UndoableEdit undoableEdit, SketchTextArea textArea) { this.undoableEdit = undoableEdit; this.caretPosition = textArea.getCaretPosition(); } diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java index 9d6151278..37d258ed1 100644 --- a/app/src/processing/app/Editor.java +++ b/app/src/processing/app/Editor.java @@ -24,11 +24,8 @@ package processing.app; import cc.arduino.packages.MonitorFactory; -import cc.arduino.view.*; -import cc.arduino.view.Event; -import cc.arduino.view.EventListener; +import cc.arduino.view.StubMenuListener; import com.jcraft.jsch.JSchException; - import jssc.SerialPortException; import processing.app.debug.*; import processing.app.forms.PasswordAuthorizationDialog; @@ -50,10 +47,17 @@ import java.util.List; import java.util.zip.*; import javax.swing.*; +import javax.swing.border.MatteBorder; import javax.swing.event.*; import javax.swing.text.*; import javax.swing.undo.*; +import org.fife.ui.rsyntaxtextarea.RSyntaxDocument; +import org.fife.ui.rsyntaxtextarea.RSyntaxTextAreaEditorKit; +import org.fife.ui.rsyntaxtextarea.RSyntaxUtilities; +import org.fife.ui.rtextarea.Gutter; +import org.fife.ui.rtextarea.RTextScrollPane; + import cc.arduino.packages.BoardPort; import cc.arduino.packages.Uploader; import cc.arduino.packages.uploaders.SerialUploader; @@ -96,7 +100,6 @@ public class Editor extends JFrame implements RunnerListener { // file, sketch, and tools menus for re-inserting items JMenu fileMenu; - JMenu sketchMenu; JMenu toolsMenu; int numTools = 0; @@ -109,10 +112,6 @@ public class Editor extends JFrame implements RunnerListener { static JMenu examplesMenu; static JMenu importMenu; - // these menus are shared so that the board and serial port selections - // are the same for all windows (since the board and serial port that are - // actually used are determined by the preferences, which are shared) - static List boardsMenus; static JMenu serialMenu; static AbstractMonitor serialMonitor; @@ -133,8 +132,8 @@ public class Editor extends JFrame implements RunnerListener { //JEditorPane editorPane; - JEditTextArea textarea; - EditorListener listener; + SketchTextArea textarea; + RTextScrollPane scrollPane; // runtime information and window placement Point sketchWindowLocation; @@ -152,14 +151,13 @@ public class Editor extends JFrame implements RunnerListener { JMenuItem undoItem, redoItem; protected UndoAction undoAction; protected RedoAction redoAction; - LastUndoableEditAwareUndoManager undo; - // used internally, and only briefly - CompoundEdit compoundEdit; FindReplace find; Runnable runHandler; Runnable presentHandler; + Runnable runAndSaveHandler; + Runnable presentAndSaveHandler; Runnable stopHandler; Runnable exportHandler; Runnable exportAppHandler; @@ -188,29 +186,25 @@ public class Editor extends JFrame implements RunnerListener { // When bringing a window to front, let the Base know addWindowListener(new WindowAdapter() { public void windowActivated(WindowEvent e) { -// System.err.println("activate"); // not coming through 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); - int offset = 0; - for (JMenu menu : boardsMenus) { - toolsMenu.insert(menu, numTools + offset); - offset++; - } - toolsMenu.insert(serialMenu, numTools + offset); } // added for 1.0.5 // http://dev.processing.org/bugs/show_bug.cgi?id=1260 public void windowDeactivated(WindowEvent e) { -// System.err.println("deactivate"); // not coming through fileMenu.remove(sketchbookMenu); fileMenu.remove(examplesMenu); - sketchMenu.remove(importMenu); - for (JMenu menu : boardsMenus) { - toolsMenu.remove(menu); + List toolsMenuItemsToRemove = new LinkedList(); + for (Component menuItem : toolsMenu.getMenuComponents()) { + if (menuItem instanceof JComponent) { + Object removeOnWindowDeactivation = ((JComponent) menuItem).getClientProperty("removeOnWindowDeactivation"); + if (removeOnWindowDeactivation != null && Boolean.valueOf(removeOnWindowDeactivation.toString())) { + toolsMenuItemsToRemove.add(menuItem); + } + } + } + for (Component menuItem : toolsMenuItemsToRemove) { + toolsMenu.remove(menuItem); } toolsMenu.remove(serialMenu); } @@ -241,10 +235,8 @@ public class Editor extends JFrame implements RunnerListener { header = new EditorHeader(this); upper.add(header); - textarea = new JEditTextArea(new PdeTextAreaDefaults()); + textarea = createTextArea(); textarea.setName("editor"); - textarea.setRightClickPopup(new TextAreaPopup()); - textarea.setHorizontalOffset(6); // assemble console panel, consisting of status area and the console itself consolePanel = new JPanel(); @@ -259,12 +251,23 @@ public class Editor extends JFrame implements RunnerListener { console.setBorder(null); consolePanel.add(console, BorderLayout.CENTER); - lineStatus = new EditorLineStatus(textarea); + lineStatus = new EditorLineStatus(); consolePanel.add(lineStatus, BorderLayout.SOUTH); - upper.add(textarea); - splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, - upper, consolePanel); + // RTextScrollPane + scrollPane = new RTextScrollPane(textarea, true); + scrollPane.setBorder(new MatteBorder(0, 6, 0, 0, Theme.getColor("editor.bgcolor"))); + scrollPane.setViewportBorder(BorderFactory.createEmptyBorder()); + scrollPane.setLineNumbersEnabled(PreferencesData.getBoolean("editor.linenumbers")); + scrollPane.setIconRowHeaderEnabled(false); + + Gutter gutter = scrollPane.getGutter(); + gutter.setBookmarkingEnabled(false); + //gutter.setBookmarkIcon(CompletionsRenderer.getIcon(CompletionType.TEMPLATE)); + gutter.setIconRowHeaderInheritsGutterBackground(true); + + upper.add(scrollPane); + splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, upper, consolePanel); splitPane.setOneTouchExpandable(true); // repaint child panes while resizing @@ -278,7 +281,7 @@ public class Editor extends JFrame implements RunnerListener { splitPane.setBorder(null); // the default size on windows is too small and kinda ugly - int dividerSize = Preferences.getInteger("editor.divider.size"); + int dividerSize = PreferencesData.getInteger("editor.divider.size"); if (dividerSize != 0) { splitPane.setDividerSize(dividerSize); } @@ -290,7 +293,7 @@ public class Editor extends JFrame implements RunnerListener { // hopefully these are no longer needed w/ swing // (har har har.. that was wishful thinking) - listener = new EditorListener(this, textarea); + // listener = new EditorListener(this, textarea); pain.add(box); // get shift down/up events so we can show the alt version of toolbar buttons @@ -310,8 +313,8 @@ public class Editor extends JFrame implements RunnerListener { // Set the minimum size for the editor window - setMinimumSize(new Dimension(Preferences.getInteger("editor.window.width.min"), - Preferences.getInteger("editor.window.height.min"))); + setMinimumSize(new Dimension(PreferencesData.getInteger("editor.window.width.min"), + PreferencesData.getInteger("editor.window.height.min"))); // System.out.println("t3"); // Bring back the general options for the editor @@ -440,47 +443,46 @@ public class Editor extends JFrame implements RunnerListener { * the app is just starting up, or the user just finished messing * with things in the Preferences window. */ - protected void applyPreferences() { + public void applyPreferences() { // apply the setting for 'use external editor' - boolean external = Preferences.getBoolean("editor.external"); + boolean external = PreferencesData.getBoolean("editor.external"); textarea.setEditable(!external); saveMenuItem.setEnabled(!external); saveAsMenuItem.setEnabled(!external); - textarea.setDisplayLineNumbers(Preferences.getBoolean("editor.linenumbers")); + textarea.setCodeFoldingEnabled(PreferencesData.getBoolean("editor.code_folding")); + scrollPane.setLineNumbersEnabled(PreferencesData.getBoolean("editor.linenumbers")); - 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); + textarea.setBackground(color); + textarea.setHighlightCurrentLine(false); + textarea.setEditable(false); } else { - Color color = Theme.getColor("editor.bgcolor"); - painter.setBackground(color); - boolean highlight = Preferences.getBoolean("editor.linehighlight"); - painter.setLineHighlightEnabled(highlight); - textarea.setCaretVisible(true); + boolean highlight = PreferencesData.getBoolean("editor.linehighlight"); + textarea.setHighlightCurrentLine(highlight); + textarea.setEditable(true); } // apply changes to the font size for the editor //TextAreaPainter painter = textarea.getPainter(); - painter.setFont(Preferences.getFont("editor.font")); + textarea.setFont(PreferencesData.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(); + // 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(); + } @@ -489,10 +491,59 @@ public class Editor extends JFrame implements RunnerListener { protected void buildMenuBar() throws Exception { JMenuBar menubar = new JMenuBar(); - menubar.add(buildFileMenu()); + final JMenu fileMenu = buildFileMenu(); + fileMenu.addMenuListener(new StubMenuListener() { + @Override + public void menuSelected(MenuEvent e) { + List components = Arrays.asList(fileMenu.getComponents()); + if (!components.contains(sketchbookMenu)) { + fileMenu.insert(sketchbookMenu, 2); + } + if (!components.contains(sketchbookMenu)) { + fileMenu.insert(examplesMenu, 3); + } + fileMenu.revalidate(); + validate(); + } + }); + menubar.add(fileMenu); + menubar.add(buildEditMenu()); - menubar.add(buildSketchMenu()); - menubar.add(buildToolsMenu()); + + final JMenu sketchMenu = new JMenu(_("Sketch")); + sketchMenu.addMenuListener(new StubMenuListener() { + + @Override + public void menuSelected(MenuEvent e) { + buildSketchMenu(sketchMenu); + sketchMenu.revalidate(); + validate(); + } + }); + buildSketchMenu(sketchMenu); + menubar.add(sketchMenu); + + final JMenu toolsMenu = buildToolsMenu(); + toolsMenu.addMenuListener(new StubMenuListener() { + @Override + public void menuSelected(MenuEvent e) { + List components = Arrays.asList(fileMenu.getComponents()); + int offset = 0; + for (JMenu menu : base.getBoardsCustomMenus()) { + if (!components.contains(menu)) { + toolsMenu.insert(menu, numTools + offset); + offset++; + } + } + if (!components.contains(serialMenu)) { + toolsMenu.insert(serialMenu, numTools + offset); + } + toolsMenu.revalidate(); + validate(); + } + }); + menubar.add(toolsMenu); + menubar.add(buildHelpMenu()); setJMenuBar(menubar); } @@ -564,30 +615,14 @@ public class Editor extends JFrame implements RunnerListener { }); fileMenu.add(saveAsMenuItem); - item = newJMenuItem(_("Upload"), 'U'); - item.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - handleExport(false); - } - }); - fileMenu.add(item); - - item = newJMenuItemShift(_("Upload Using Programmer"), 'U'); - item.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - handleExport(true); - } - }); - fileMenu.add(item); - fileMenu.addSeparator(); item = newJMenuItemShift(_("Page Setup"), 'P'); item.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - handlePageSetup(); - } - }); + public void actionPerformed(ActionEvent e) { + handlePageSetup(); + } + }); fileMenu.add(item); item = newJMenuItem(_("Print"), 'P'); @@ -624,25 +659,41 @@ public class Editor extends JFrame implements RunnerListener { } - protected JMenu buildSketchMenu() { - JMenuItem item; - sketchMenu = new JMenu(_("Sketch")); + protected void buildSketchMenu(JMenu sketchMenu) { + sketchMenu.removeAll(); - item = newJMenuItem(_("Verify / Compile"), 'R'); + JMenuItem item = newJMenuItem(_("Verify / Compile"), 'R'); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { - handleRun(false); + handleRun(false, Editor.this.presentHandler, Editor.this.runHandler); } }); sketchMenu.add(item); -// item = newJMenuItemShift("Verify / Compile (verbose)", 'R'); -// item.addActionListener(new ActionListener() { -// public void actionPerformed(ActionEvent e) { -// handleRun(true); -// } -// }); -// sketchMenu.add(item); + item = newJMenuItem(_("Upload"), 'U'); + item.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + handleExport(false); + } + }); + sketchMenu.add(item); + + item = newJMenuItemShift(_("Upload Using Programmer"), 'U'); + item.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + handleExport(true); + } + }); + sketchMenu.add(item); + + + item = newJMenuItemAlt(_("Export compiled Binary"), 'S'); + item.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + handleRun(false, Editor.this.presentAndSaveHandler, Editor.this.runAndSaveHandler); + } + }); + sketchMenu.add(item); // item = new JMenuItem("Stop"); // item.addActionListener(new ActionListener() { @@ -654,83 +705,69 @@ public class Editor extends JFrame implements RunnerListener { sketchMenu.addSeparator(); + 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()); + if (importMenu == null) { - importMenu = new JMenu(_("Import Library...")); + importMenu = new JMenu(_("Include Library")); MenuScroller.setScrollerFor(importMenu); 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(); - } - }); + public void actionPerformed(ActionEvent e) { + sketch.handleAddFile(); + } + }); sketchMenu.add(item); - - return sketchMenu; } protected JMenu buildToolsMenu() throws Exception { toolsMenu = new JMenu(_("Tools")); - JMenu menu = toolsMenu; - JMenuItem item; - addInternalTools(menu); + addInternalTools(toolsMenu); - item = newJMenuItemShift(_("Serial Monitor"), 'M'); + JMenuItem item = newJMenuItemShift(_("Serial Monitor"), 'M'); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { handleSerial(); } }); - menu.add(item); + toolsMenu.add(item); - addTools(menu, Base.getToolsFolder()); + addTools(toolsMenu, Base.getToolsFolder()); File sketchbookTools = new File(Base.getSketchbookFolder(), "tools"); - addTools(menu, sketchbookTools); + addTools(toolsMenu, sketchbookTools); - menu.addSeparator(); + toolsMenu.addSeparator(); - numTools = menu.getItemCount(); + numTools = toolsMenu.getItemCount(); // XXX: DAM: these should probably be implemented using the Tools plugin // API, if possible (i.e. if it supports custom actions, etc.) - if (boardsMenus == null) { - boardsMenus = new LinkedList(); - - JMenu boardsMenu = new JMenu(_("Board")); - MenuScroller.setScrollerFor(boardsMenu); - Editor.boardsMenus.add(boardsMenu); - toolsMenu.add(boardsMenu); - - base.rebuildBoardsMenu(toolsMenu, this); - //Debug: rebuild imports - importMenu.removeAll(); - base.rebuildImportMenu(importMenu); + for (JMenu menu : base.getBoardsCustomMenus()) { + toolsMenu.add(menu); } if (serialMenu == null) serialMenu = new JMenu(_("Port")); populatePortMenu(); - menu.add(serialMenu); - menu.addSeparator(); + toolsMenu.add(serialMenu); + toolsMenu.addSeparator(); JMenu programmerMenu = new JMenu(_("Programmer")); base.rebuildProgrammerMenu(programmerMenu); - menu.add(programmerMenu); + toolsMenu.add(programmerMenu); item = new JMenuItem(_("Burn Bootloader")); item.addActionListener(new ActionListener() { @@ -738,18 +775,42 @@ public class Editor extends JFrame implements RunnerListener { handleBurnBootloader(); } }); - menu.add(item); + toolsMenu.add(item); - menu.addMenuListener(new MenuListener() { - public void menuCanceled(MenuEvent e) {} - public void menuDeselected(MenuEvent e) {} + toolsMenu.addMenuListener(new StubMenuListener() { public void menuSelected(MenuEvent e) { //System.out.println("Tools menu selected."); populatePortMenu(); + for (Component c : toolsMenu.getMenuComponents()) { + if ((c instanceof JMenu) && c.isVisible()) { + JMenu menu = (JMenu)c; + String name = menu.getText(); + if (name == null) continue; + String basename = name; + int index = name.indexOf(':'); + if (index > 0) basename = name.substring(0, index); + String sel = null; + int count = menu.getItemCount(); + for (int i=0; i < count; i++) { + JMenuItem item = menu.getItem(i); + if (item != null && item.isSelected()) { + sel = item.getText(); + if (sel != null) break; + } + } + if (sel == null) { + if (!name.equals(basename)) menu.setText(basename); + } else { + if (sel.length() > 17) sel = sel.substring(0, 16) + "..."; + String newname = basename + ": \"" + sel + "\""; + if (!name.equals(newname)) menu.setText(newname); + } + } + } } }); - return menu; + return toolsMenu; } @@ -895,6 +956,44 @@ public class Editor extends JFrame implements RunnerListener { } + protected SketchTextArea createTextArea() throws IOException { + final SketchTextArea textArea = new SketchTextArea(base.getPdeKeywords()); + textArea.requestFocusInWindow(); + textArea.setMarkOccurrences(PreferencesData.getBoolean("editor.advanced")); + textArea.setMarginLineEnabled(false); + textArea.setCodeFoldingEnabled(PreferencesData.getBoolean("editor.code_folding")); + textArea.setAntiAliasingEnabled(PreferencesData.getBoolean("editor.antialias")); + textArea.setTabsEmulated(PreferencesData.getBoolean("editor.tabs.expand")); + textArea.setTabSize(PreferencesData.getInteger("editor.tabs.size")); + textArea.setEditorListener(new EditorListener(this)); + textArea.addHyperlinkListener(new HyperlinkListener() { + @Override + public void hyperlinkUpdate(HyperlinkEvent hyperlinkEvent) { + try { + base.getPlatform().openURL(hyperlinkEvent.getURL().toExternalForm()); + } catch (Exception e) { + Base.showWarning(e.getMessage(), e.getMessage(), e); + } + } + }); + textArea.addCaretListener(new CaretListener() { + + @Override + public void caretUpdate(CaretEvent e) { + int lineStart = textArea.getDocument().getDefaultRootElement().getElementIndex(e.getMark()); + int lineEnd = textArea.getDocument().getDefaultRootElement().getElementIndex(e.getDot()); + + lineStatus.set(lineStart, lineEnd); + } + + }); + + ToolTipManager.sharedInstance().registerComponent(textArea); + + configurePopupMenu(textArea); + return textArea; + } + protected JMenuItem createToolMenuItem(String className) { try { Class toolClass = Class.forName(className); @@ -947,22 +1046,15 @@ public class Editor extends JFrame implements RunnerListener { class SerialMenuListener implements ActionListener { - private final Frame parent; private final String serialPort; - private final String warning; - public SerialMenuListener(Frame parent, String serialPort, String warning) { - this.parent = parent; + public SerialMenuListener(String serialPort) { this.serialPort = serialPort; - this.warning = warning; } public void actionPerformed(ActionEvent e) { selectSerialPort(serialPort); base.onBoardOrPortChange(); - if (warning != null && !Preferences.getBoolean("uncertifiedBoardWarning_dontShowMeAgain")) { - SwingUtilities.invokeLater(new ShowUncertifiedBoardWarning(parent)); - } } } @@ -1011,11 +1103,11 @@ public class Editor extends JFrame implements RunnerListener { protected void populatePortMenu() { serialMenu.removeAll(); - String selectedPort = Preferences.get("serial.port"); + String selectedPort = PreferencesData.get("serial.port"); List ports = Base.getDiscoveryManager().discovery(); - ports = Base.getPlatform().filterPorts(ports, Preferences.getBoolean("serial.ports.showall")); + ports = Base.getPlatform().filterPorts(ports, PreferencesData.getBoolean("serial.ports.showall")); Collections.sort(ports, new Comparator() { @Override @@ -1038,13 +1130,15 @@ public class Editor extends JFrame implements RunnerListener { } else { lastProtocolTranslated = port.getProtocol(); } - serialMenu.add(new JMenuItem(_(lastProtocolTranslated))); + JMenuItem lastProtocolMenuItem = new JMenuItem(_(lastProtocolTranslated)); + lastProtocolMenuItem.setEnabled(false); + serialMenu.add(lastProtocolMenuItem); } String address = port.getAddress(); String label = port.getLabel(); JCheckBoxMenuItem item = new JCheckBoxMenuItem(label, address.equals(selectedPort)); - item.addActionListener(new SerialMenuListener(this, address, port.getPrefs().get("warning"))); + item.addActionListener(new SerialMenuListener(address)); serialMenu.add(item); } @@ -1097,35 +1191,79 @@ public class Editor extends JFrame implements RunnerListener { item = new JMenuItem(_("Getting Started")); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { - Base.showGettingStarted(); + Base.showArduinoGettingStarted(); } }); menu.add(item); item = new JMenuItem(_("Environment")); item.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - Base.showEnvironment(); - } - }); + 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(); - } - }); + 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(); - } - }); + public void actionPerformed(ActionEvent e) { + Base.showReference(); + } + }); menu.add(item); + menu.addSeparator(); + + item = new JMenuItem(_("Galileo Help")); + item.setEnabled(false); + menu.add(item); + + item = new JMenuItem(_("Getting Started")); + item.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + Base.showReference("reference/Galileo_help_files", "ArduinoIDE_guide_galileo"); + } + }); + menu.add(item); + item = new JMenuItem(_("Troubleshooting")); + item.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + Base.showReference("reference/Galileo_help_files", "Guide_Troubleshooting_Galileo");; + } + }); + menu.add(item); + + menu.addSeparator(); + + item = new JMenuItem(_("Edison Help")); + item.setEnabled(false); + menu.add(item); + + item = new JMenuItem(_("Getting Started")); + item.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + Base.showReference("reference/Edison_help_files", "ArduinoIDE_guide_edison"); + } + }); + menu.add(item); + item = new JMenuItem(_("Troubleshooting")); + item.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + Base.showReference("reference/Edison_help_files", "Guide_Troubleshooting_Edison");; + } + }); + menu.add(item); + + menu.addSeparator(); + item = newJMenuItemShift(_("Find in Reference"), 'F'); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { @@ -1280,50 +1418,55 @@ public class Editor extends JFrame implements RunnerListener { item = newJMenuItem(_("Find..."), 'F'); item.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - if (find == null) { - find = new FindReplace(Editor.this); - } - if (getSelectedText()!= null) find.setFindText( getSelectedText() ); - //new FindReplace(Editor.this).show(); - find.setVisible(true); - //find.setVisible(true); + public void actionPerformed(ActionEvent e) { + if (find == null) { + find = new FindReplace(Editor.this); } - }); + if (!OSUtils.isMacOS() && getSelectedText() != null) { + find.setFindText(getSelectedText()); + } + find.setLocationRelativeTo(Editor.this); + 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.findNext(); - } + public void actionPerformed(ActionEvent e) { + if (find != null) { + find.findNext(); } - }); + } + }); menu.add(item); item = newJMenuItemShift(_("Find Previous"), 'G'); item.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - if (find != null) { - find.findPrevious(); - } + public void actionPerformed(ActionEvent e) { + if (find != null) { + find.findPrevious(); } - }); + } + }); menu.add(item); - item = newJMenuItem(_("Use Selection For Find"), 'E'); - item.addActionListener(new ActionListener() { + if (OSUtils.isMacOS()) { + item = newJMenuItem(_("Use Selection For Find"), 'E'); + item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if (find == null) { find = new FindReplace(Editor.this); } - find.setFindText( getSelectedText() ); + if (getSelectedText() != null) { + find.setFindText(getSelectedText()); + } + find.setLocationRelativeTo(Editor.this); + find.setVisible(true); } }); - menu.add(item); + menu.add(item); + } return menu; } @@ -1374,24 +1517,18 @@ public class Editor extends JFrame implements RunnerListener { public void actionPerformed(ActionEvent e) { try { - undo.undo(); + textarea.undoLastAction(); sketch.setModified(true); } catch (CannotUndoException ex) { //System.out.println("Unable to undo: " + ex); //ex.printStackTrace(); } - if (undo.getLastUndoableEdit() != null && undo.getLastUndoableEdit() instanceof CaretAwareUndoableEdit) { - CaretAwareUndoableEdit undoableEdit = (CaretAwareUndoableEdit) undo.getLastUndoableEdit(); - int nextCaretPosition = undoableEdit.getCaretPosition() - 1; - if (nextCaretPosition >= 0 && textarea.getDocumentLength() > nextCaretPosition) { - textarea.setCaretPosition(nextCaretPosition); - } - } - updateUndoState(); - redoAction.updateRedoState(); } protected void updateUndoState() { + + UndoManager undo = textarea.getUndoManager(); + if (undo.canUndo()) { this.setEnabled(true); undoItem.setEnabled(true); @@ -1415,21 +1552,17 @@ public class Editor extends JFrame implements RunnerListener { public void actionPerformed(ActionEvent e) { try { - undo.redo(); + textarea.redoLastAction(); sketch.setModified(true); } catch (CannotRedoException ex) { //System.out.println("Unable to redo: " + ex); //ex.printStackTrace(); } - if (undo.getLastUndoableEdit() != null && undo.getLastUndoableEdit() instanceof CaretAwareUndoableEdit) { - CaretAwareUndoableEdit undoableEdit = (CaretAwareUndoableEdit) undo.getLastUndoableEdit(); - textarea.setCaretPosition(undoableEdit.getCaretPosition()); - } - updateRedoState(); - undoAction.updateUndoState(); } protected void updateRedoState() { + UndoManager undo = textarea.getUndoManager(); + if (undo.canRedo()) { redoItem.setEnabled(true); redoItem.setText(undo.getRedoPresentationName()); @@ -1453,11 +1586,17 @@ public class Editor extends JFrame implements RunnerListener { // abstract from the editor in this fashion. - public void setHandlers(Runnable runHandler, Runnable presentHandler, + public void setHandlers(Runnable runHandler, + Runnable presentHandler, + Runnable runAndSaveHandler, + Runnable presentAndSaveHandler, Runnable stopHandler, - Runnable exportHandler, Runnable exportAppHandler) { + Runnable exportHandler, + Runnable exportAppHandler) { this.runHandler = runHandler; this.presentHandler = presentHandler; + this.runAndSaveHandler = runAndSaveHandler; + this.presentAndSaveHandler = presentAndSaveHandler; this.stopHandler = stopHandler; this.exportHandler = exportHandler; this.exportAppHandler = exportAppHandler; @@ -1467,6 +1606,8 @@ public class Editor extends JFrame implements RunnerListener { public void resetHandlers() { runHandler = new BuildHandler(); presentHandler = new BuildHandler(true); + runAndSaveHandler = new BuildHandler(false, true); + presentAndSaveHandler = new BuildHandler(true, true); stopHandler = new DefaultStopHandler(); exportHandler = new DefaultExportHandler(); exportAppHandler = new DefaultExportAppHandler(); @@ -1485,13 +1626,13 @@ public class Editor extends JFrame implements RunnerListener { /** - * Get the JEditTextArea object for use (not recommended). This should only + * Get the TextArea 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. + * which will not use TextArea. */ - public JEditTextArea getTextArea() { + public SketchTextArea getTextArea() { return textarea; } @@ -1508,7 +1649,11 @@ public class Editor extends JFrame implements RunnerListener { * Get a range of text from the current buffer. */ public String getText(int start, int stop) { - return textarea.getText(start, stop - start); + try { + return textarea.getText(start, stop - start); + } catch (BadLocationException e) { + return null; + } } @@ -1516,20 +1661,10 @@ public class Editor extends JFrame implements RunnerListener { * 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 @@ -1555,15 +1690,10 @@ public class Editor extends JFrame implements RunnerListener { public void setSelectedText(String what) { - textarea.setSelectedText(what); + textarea.replaceSelection(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); } @@ -1599,7 +1729,7 @@ public class Editor extends JFrame implements RunnerListener { * Get the end point of the current selection. */ public int getSelectionStop() { - return textarea.getSelectionStop(); + return textarea.getSelectionEnd(); } @@ -1607,18 +1737,11 @@ public class Editor extends JFrame implements RunnerListener { * 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(); + try { + return textarea.getText(textarea.getLineStartOffset(line), textarea.getLineEndOffset(line)); + } catch (BadLocationException e) { + return ""; + } } @@ -1626,7 +1749,11 @@ public class Editor extends JFrame implements RunnerListener { * Get character offset for the start of a given line of text. */ public int getLineStartOffset(int line) { - return textarea.getLineStartOffset(line); + try { + return textarea.getLineStartOffset(line); + } catch (BadLocationException e) { + return -1; + } } @@ -1634,7 +1761,11 @@ public class Editor extends JFrame implements RunnerListener { * Get character offset for end of a given line of text. */ public int getLineStopOffset(int line) { - return textarea.getLineStopOffset(line); + try { + return textarea.getLineEndOffset(line); + } catch (BadLocationException e) { + return -1; + } } @@ -1644,31 +1775,10 @@ public class Editor extends JFrame implements RunnerListener { 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(); + return scrollPane.getVerticalScrollBar().getValue(); } @@ -1679,15 +1789,12 @@ public class Editor extends JFrame implements RunnerListener { * Switch between tabs, this swaps out the Document object * that's currently being manipulated. */ - protected void setCode(SketchCodeDocument codeDoc) { - SyntaxDocument document = (SyntaxDocument) codeDoc.getDocument(); + protected void setCode(final SketchCodeDocument codeDoc) { + RSyntaxDocument document = (RSyntaxDocument) codeDoc.getDocument(); if (document == null) { // this document not yet inited - document = new SyntaxDocument(); - codeDoc.setDocument(document); - - // turn on syntax highlighting - document.setTokenMarker(new PdeKeywords()); + document = new RSyntaxDocument(new ArduinoTokenMakerFactory(base.getPdeKeywords()), RSyntaxDocument.SYNTAX_STYLE_CPLUSPLUS); + document.putProperty(PlainDocument.tabSizeAttribute, PreferencesData.getInteger("editor.tabs.size")); // insert the program text into the document object try { @@ -1695,37 +1802,39 @@ public class Editor extends JFrame implements RunnerListener { } 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(new CaretAwareUndoableEdit(e.getEdit(), textarea)); - } else if (undo != null) { - undo.addEdit(new CaretAwareUndoableEdit(e.getEdit(), textarea)); - } - if (compoundEdit != null || undo != null) { - sketch.setModified(true); - undoAction.updateUndoState(); - redoAction.updateRedoState(); - } - } - }); + + codeDoc.setDocument(document); } - // update the document object that's in use - textarea.setDocument(document, - codeDoc.getSelectionStart(), codeDoc.getSelectionStop(), - codeDoc.getScrollPosition()); - + if(codeDoc.getUndo() == null){ + codeDoc.setUndo(new LastUndoableEditAwareUndoManager(textarea, this)); + document.addUndoableEditListener(codeDoc.getUndo()); + } + + // Update the document object that's in use + textarea.switchDocument(document, codeDoc.getUndo()); + + // HACK multiple tabs: for update Listeners of Gutter, forcin call: Gutter.setTextArea(RTextArea) + // BUG: https://github.com/bobbylight/RSyntaxTextArea/issues/84 + scrollPane.setViewportView(textarea); + + textarea.select(codeDoc.getSelectionStart(), codeDoc.getSelectionStop()); textarea.requestFocus(); // get the caret blinking - - this.undo = codeDoc.getUndo(); - undoAction.updateUndoState(); - redoAction.updateRedoState(); + + final int position = codeDoc.getScrollPosition(); + + // invokeLater: Expect the document to be rendered correctly to set the new position + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + scrollPane.getVerticalScrollBar().setValue(position); + undoAction.updateUndoState(); + redoAction.updateRedoState(); + } + }); + } @@ -1737,7 +1846,6 @@ public class Editor extends JFrame implements RunnerListener { */ public void handleCut() { textarea.cut(); - sketch.setModified(true); } @@ -1764,7 +1872,6 @@ public class Editor extends JFrame implements RunnerListener { */ public void handlePaste() { textarea.paste(); - sketch.setModified(true); } @@ -1775,104 +1882,68 @@ public class Editor extends JFrame implements RunnerListener { 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(); + /** + * Begins an "atomic" edit. This method is called when TextArea + * KNOWS that some edits should be compound automatically, such as the playing back of a macro. + * + * @see #endInternalAtomicEdit() + */ + public void beginInternalAtomicEdit(){ + textarea.getUndoManager().beginInternalAtomicEdit(); } + /** + * Ends an "atomic" edit. + * + * @see #beginInternalAtomicEdit() + */ + public void endInternalAtomicEdit(){ + textarea.getUndoManager().endInternalAtomicEdit(); + } + + + void handleCommentUncomment() { + + Action action = textarea.getActionMap().get(RSyntaxTextAreaEditorKit.rstaToggleCommentAction); + action.actionPerformed(null); + + } + protected void handleIndentOutdent(boolean indent) { - int tabSize = Preferences.getInteger("editor.tabs.size"); - String tabString = Editor.EMPTY.substring(0, tabSize); + if (indent) { - startCompoundEdit(); + int caretPosition = textarea.getCaretPosition(); + boolean noSelec = !textarea.isSelectionActive(); - 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(""); + // if no selection, focus on first char. + if (noSelec) { + try { + int line = textarea.getCaretLineNumber(); + int startOffset = textarea.getLineStartOffset(line); + textarea.setCaretPosition(startOffset); + } catch (BadLocationException e) { } } + + // Insert Tab or Spaces.. + Action action = textarea.getActionMap().get(RSyntaxTextAreaEditorKit.insertTabAction); + action.actionPerformed(null); + + if (noSelec) { + textarea.setCaretPosition(caretPosition); + } + + } else { + Action action = textarea.getActionMap().get(RSyntaxTextAreaEditorKit.rstaDecreaseIndentAction); + action.actionPerformed(null); } - // 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(); } + + /** Checks the preferences you are in external editing mode */ + public static boolean isExternalMode(){ + return PreferencesData.getBoolean("editor.external"); + } protected String getCurrentKeyword() { String text = ""; @@ -1918,7 +1989,7 @@ public class Editor extends JFrame implements RunnerListener { protected void handleFindReference() { String text = getCurrentKeyword(); - String referenceFile = PdeKeywords.getReference(text); + String referenceFile = base.getPdeKeywords().getReference(text); if (referenceFile == null) { statusNotice(I18n.format(_("No reference available for \"{0}\""), text)); } else { @@ -1933,10 +2004,12 @@ public class Editor extends JFrame implements RunnerListener { /** * Implements Sketch → Run. * @param verbose Set true to run with verbose output. + * @param verboseHandler + * @param nonVerboseHandler */ - public void handleRun(final boolean verbose) { + public void handleRun(final boolean verbose, Runnable verboseHandler, Runnable nonVerboseHandler) { internalCloseRunner(); - if (Preferences.getBoolean("editor.save_on_verify")) { + if (PreferencesData.getBoolean("editor.save_on_verify")) { if (sketch.isModified() && !sketch.isReadOnly()) { handleSave(true); } @@ -1949,32 +2022,39 @@ public class Editor extends JFrame implements RunnerListener { 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")) { + if (PreferencesData.getBoolean("console.auto_clear")) { console.clear(); } // Cannot use invokeLater() here, otherwise it gets // placed on the event thread and causes a hang--bad idea all around. - new Thread(verbose ? presentHandler : runHandler).start(); + new Thread(verbose ? verboseHandler : nonVerboseHandler).start(); } class BuildHandler implements Runnable { private final boolean verbose; + private final boolean saveHex; public BuildHandler() { this(false); } public BuildHandler(boolean verbose) { + this(verbose, false); + } + + public BuildHandler(boolean verbose, boolean saveHex) { this.verbose = verbose; + this.saveHex = saveHex; } @Override public void run() { try { + textarea.removeAllLineHighlights(); sketch.prepare(); - sketch.build(verbose); + sketch.build(verbose, saveHex); statusNotice(_("Done compiling.")); } catch (PreferencesMapException e) { statusError(I18n.format( @@ -2154,7 +2234,7 @@ public class Editor extends JFrame implements RunnerListener { sketch.setCurrentCode(codeIndex); textarea.select(selStart, selStop); - textarea.setScrollPosition(scrollPos); + scrollPane.getVerticalScrollBar().setValue(scrollPos); } @@ -2245,16 +2325,14 @@ public class Editor extends JFrame implements RunnerListener { return false; } header.rebuild(); - // Set the title of the window to "sketch_070752a - Processing 0126" - setTitle(I18n.format(_("{0} | Arduino {1}"), sketch.getName(), - BaseNoGui.VERSION_NAME)); + setTitle(I18n.format(_("{0} | Arduino {1}"), sketch.getName(), BaseNoGui.VERSION_NAME_LONG)); // 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(); + PreferencesData.save(); // opening was successful return true; @@ -2279,6 +2357,7 @@ public class Editor extends JFrame implements RunnerListener { public boolean handleSave(boolean immediately) { //stopRunner(); handleStop(); // 0136 + textarea.removeAllLineHighlights(); if (untitled) { return handleSaveAs(); @@ -2375,7 +2454,7 @@ public class Editor extends JFrame implements RunnerListener { I18n.format( _("Serial port {0} not found.\n" + "Retry the upload with another serial port?"), - Preferences.get("serial.port") + PreferencesData.get("serial.port") ), "Serial port not found", JOptionPane.PLAIN_MESSAGE, @@ -2405,7 +2484,7 @@ public class Editor extends JFrame implements RunnerListener { * hitting export twice, quickly, and horking things up. */ synchronized public void handleExport(final boolean usingProgrammer) { - if (Preferences.getBoolean("editor.save_on_verify")) { + if (PreferencesData.getBoolean("editor.save_on_verify")) { if (sketch.isModified() && !sketch.isReadOnly()) { handleSave(true); } @@ -2548,10 +2627,10 @@ public class Editor extends JFrame implements RunnerListener { } } - BoardPort port = Base.getDiscoveryManager().find(Preferences.get("serial.port")); + BoardPort port = Base.getDiscoveryManager().find(PreferencesData.get("serial.port")); if (port == null) { - statusError(I18n.format("Board at {0} is not available", Preferences.get("serial.port"))); + statusError(I18n.format("Board at {0} is not available", PreferencesData.get("serial.port"))); return; } @@ -2560,7 +2639,7 @@ public class Editor extends JFrame implements RunnerListener { boolean success = false; do { - if (serialMonitor.requiresAuthorization() && !Preferences.has(serialMonitor.getAuthorizationKey())) { + if (serialMonitor.requiresAuthorization() && !PreferencesData.has(serialMonitor.getAuthorizationKey())) { PasswordAuthorizationDialog dialog = new PasswordAuthorizationDialog(this, _("Type board password to access its console")); dialog.setLocationRelativeTo(this); dialog.setVisible(true); @@ -2570,7 +2649,7 @@ public class Editor extends JFrame implements RunnerListener { return; } - Preferences.set(serialMonitor.getAuthorizationKey(), dialog.getPassword()); + PreferencesData.set(serialMonitor.getAuthorizationKey(), dialog.getPassword()); } try { @@ -2591,7 +2670,7 @@ public class Editor extends JFrame implements RunnerListener { statusError(e); } finally { if (serialMonitor.requiresAuthorization() && !success) { - Preferences.remove(serialMonitor.getAuthorizationKey()); + PreferencesData.remove(serialMonitor.getAuthorizationKey()); } } @@ -2655,9 +2734,9 @@ public class Editor extends JFrame implements RunnerListener { } if (pageFormat != null) { //System.out.println("setting page format " + pageFormat); - printerJob.setPrintable(textarea.getPainter(), pageFormat); + printerJob.setPrintable(textarea, pageFormat); } else { - printerJob.setPrintable(textarea.getPainter()); + printerJob.setPrintable(textarea); } // set the name of the job to the code name printerJob.setJobName(sketch.getCurrentCode().getPrettyName()); @@ -2714,7 +2793,7 @@ public class Editor extends JFrame implements RunnerListener { // 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) { + if (getLineText(line).length() == 0) { // The last line may be zero length, meaning nothing to select. // If so, back up one more line. line--; @@ -2723,8 +2802,12 @@ public class Editor extends JFrame implements RunnerListener { if (line < 0 || line >= textarea.getLineCount()) { System.err.println(I18n.format(_("Bad error line: {0}"), line)); } else { - textarea.select(textarea.getLineStartOffset(line), - textarea.getLineStopOffset(line) - 1); + try { + textarea.addLineHighlight(line, new Color(1, 0, 0, 0.2f)); + textarea.setCaretPosition(textarea.getLineStartOffset(line)); + } catch (BadLocationException e1) { + e1.printStackTrace(); + } } } } @@ -2767,154 +2850,109 @@ public class Editor extends JFrame implements RunnerListener { protected void onBoardOrPortChange() { Map boardPreferences = Base.getBoardPreferences(); - lineStatus.setBoardName(boardPreferences.get("name")); - lineStatus.setSerialPort(Preferences.get("serial.port")); + if (boardPreferences != null) + lineStatus.setBoardName(boardPreferences.get("name")); + else + lineStatus.setBoardName("-"); + lineStatus.setSerialPort(PreferencesData.get("serial.port")); lineStatus.repaint(); } - /** - * Returns the edit popup menu. - */ - class TextAreaPopup extends JPopupMenu { - //private String currentDir = System.getProperty("user.dir"); - private String referenceFile = null; + protected void configurePopupMenu(final SketchTextArea textarea){ - private JMenuItem cutItem; - private JMenuItem copyItem; - private JMenuItem discourseItem; - private JMenuItem referenceItem; - private JMenuItem openURLItem; - private JSeparator openURLItemSeparator; + JPopupMenu menu = textarea.getPopupMenu(); - private String clickedURL; + menu.addSeparator(); - public TextAreaPopup() { - openURLItem = new JMenuItem(_("Open URL")); - openURLItem.addActionListener(new ActionListener() { + JMenuItem item = createToolMenuItem("cc.arduino.packages.formatter.AStyle"); + item.setName("menuToolsAutoFormat"); + + menu.add(item); + + item = newJMenuItem(_("Comment/Uncomment"), '/'); + item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { - Base.openURL(clickedURL); + handleCommentUncomment(); } - }); - add(openURLItem); + }); + menu.add(item); - openURLItemSeparator = new JSeparator(); - add(openURLItemSeparator); - - cutItem = new JMenuItem(_("Cut")); - cutItem.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - handleCut(); - } - }); - add(cutItem); - - copyItem = new JMenuItem(_("Copy")); - copyItem.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - handleCopy(); - } - }); - add(copyItem); - - discourseItem = new JMenuItem(_("Copy for Forum")); - discourseItem.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - handleDiscourseCopy(); - } - }); - add(discourseItem); - - discourseItem = new JMenuItem(_("Copy as HTML")); - discourseItem.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - handleHTMLCopy(); - } - }); - add(discourseItem); - - JMenuItem item = new JMenuItem(_("Paste")); - item.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - handlePaste(); - } - }); - add(item); - - item = new JMenuItem(_("Select All")); - item.addActionListener(new ActionListener() { + item = newJMenuItem(_("Increase Indent"), ']'); + item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { - handleSelectAll(); + handleIndentOutdent(true); } - }); - add(item); + }); + menu.add(item); - addSeparator(); + item = newJMenuItem(_("Decrease Indent"), '['); + item.setName("menuDecreaseIndent"); + item.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + handleIndentOutdent(false); + } + }); + menu.add(item); - item = new JMenuItem(_("Comment/Uncomment")); - item.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - handleCommentUncomment(); - } - }); - add(item); + item = new JMenuItem(_("Copy for Forum")); + item.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + handleDiscourseCopy(); + } + }); + menu.add(item); - item = new JMenuItem(_("Increase Indent")); - item.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - handleIndentOutdent(true); - } - }); - add(item); + item = new JMenuItem(_("Copy as HTML")); + item.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + handleHTMLCopy(); + } + }); + menu.add(item); - item = new JMenuItem(_("Decrease Indent")); - item.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - handleIndentOutdent(false); - } - }); - add(item); + final JMenuItem referenceItem = new JMenuItem(_("Find in Reference")); + referenceItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + handleFindReference(); + } + }); + menu.add(referenceItem); - addSeparator(); + final JMenuItem openURLItem = new JMenuItem(_("Open URL")); + openURLItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + Base.openURL(e.getActionCommand()); + } + }); + menu.add(openURLItem); + + menu.addPopupMenuListener(new PopupMenuListener() { - referenceItem = new JMenuItem(_("Find in Reference")); - referenceItem.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - handleFindReference(); - } - }); - add(referenceItem); - } - - // if no text is selected, disable copy and cut menu items - public void show(Component component, int x, int y) { - int lineNo = textarea.getLineOfOffset(textarea.xyToOffset(x, y)); - int offset = textarea.xToOffset(lineNo, x); - String line = textarea.getLineText(lineNo); - clickedURL = textarea.checkClickedURL(line, offset); - if (clickedURL != null) { - openURLItem.setVisible(true); - openURLItemSeparator.setVisible(true); - } else { - openURLItem.setVisible(false); - openURLItemSeparator.setVisible(false); + @Override + public void popupMenuWillBecomeVisible(PopupMenuEvent e) { + String referenceFile = base.getPdeKeywords().getReference(getCurrentKeyword()); + referenceItem.setEnabled(referenceFile != null); + + int offset = textarea.getCaretPosition(); + org.fife.ui.rsyntaxtextarea.Token token = RSyntaxUtilities.getTokenAtOffset(textarea, offset); + if (token != null && token.isHyperlink()) { + openURLItem.setEnabled(true); + openURLItem.setActionCommand(token.getLexeme()); + } else { + openURLItem.setEnabled(false); + } } - if (textarea.isSelectionActive()) { - cutItem.setEnabled(true); - copyItem.setEnabled(true); - discourseItem.setEnabled(true); - - } else { - cutItem.setEnabled(false); - copyItem.setEnabled(false); - discourseItem.setEnabled(false); + @Override + public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { } - referenceFile = PdeKeywords.getReference(getCurrentKeyword()); - referenceItem.setEnabled(referenceFile != null); + @Override + public void popupMenuCanceled(PopupMenuEvent e) { + } + }); - super.show(component, x, y); - } } + } diff --git a/app/src/processing/app/EditorConsole.java b/app/src/processing/app/EditorConsole.java index 8c4910093..a2116f8b4 100644 --- a/app/src/processing/app/EditorConsole.java +++ b/app/src/processing/app/EditorConsole.java @@ -68,7 +68,7 @@ public class EditorConsole extends JScrollPane { public EditorConsole(Editor _editor) { editor = _editor; - int maxLineCount = Preferences.getInteger("console.length"); + int maxLineCount = PreferencesData.getInteger("console.length"); consoleDoc = new BufferedStyledDocument(4000, maxLineCount); consoleTextPane = new JTextPane(consoleDoc); @@ -84,7 +84,7 @@ public class EditorConsole extends JScrollPane { Color fgColorOut = Theme.getColor("console.output.color"); Color fgColorErr = Theme.getColor("console.error.color"); Font consoleFont = Theme.getFont("console.font"); - Font editorFont = Preferences.getFont("editor.font"); + Font editorFont = PreferencesData.getFont("editor.font"); Font font = new Font(consoleFont.getName(), consoleFont.getStyle(), editorFont.getSize()); stdStyle = new SimpleAttributeSet(); @@ -112,7 +112,7 @@ public class EditorConsole extends JScrollPane { // and size window accordingly FontMetrics metrics = getFontMetrics(font); int height = metrics.getAscent() + metrics.getDescent(); - int lines = Preferences.getInteger("console.lines"); + int lines = PreferencesData.getInteger("console.lines"); 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)); diff --git a/app/src/processing/app/EditorConsoleStream.java b/app/src/processing/app/EditorConsoleStream.java index 06e232673..6ad0a336a 100644 --- a/app/src/processing/app/EditorConsoleStream.java +++ b/app/src/processing/app/EditorConsoleStream.java @@ -1,5 +1,7 @@ package processing.app; +import cc.arduino.files.DeleteFilesOnShutdown; + import static processing.app.I18n._; import java.io.File; @@ -33,19 +35,19 @@ class EditorConsoleStream extends OutputStream { // The files and folders are not deleted on exit because they may be // needed for debugging or bug reporting. tempFolder = Base.createTempFolder("console"); - tempFolder.deleteOnExit(); + DeleteFilesOnShutdown.add(tempFolder); try { - String outFileName = Preferences.get("console.output.file"); + String outFileName = PreferencesData.get("console.output.file"); if (outFileName != null) { outFile = new File(tempFolder, outFileName); - outFile.deleteOnExit(); + DeleteFilesOnShutdown.add(outFile); stdoutFile = new FileOutputStream(outFile); } - String errFileName = Preferences.get("console.error.file"); + String errFileName = PreferencesData.get("console.error.file"); if (errFileName != null) { errFile = new File(tempFolder, errFileName); - errFile.deleteOnExit(); + DeleteFilesOnShutdown.add(errFile); stderrFile = new FileOutputStream(errFile); } } catch (IOException e) { @@ -56,7 +58,7 @@ class EditorConsoleStream extends OutputStream { consoleOut = new PrintStream(new EditorConsoleStream(false)); consoleErr = new PrintStream(new EditorConsoleStream(true)); - if (Preferences.getBoolean("console")) { + if (PreferencesData.getBoolean("console")) { try { System.setOut(consoleOut); System.setErr(consoleErr); diff --git a/app/src/processing/app/EditorLineStatus.java b/app/src/processing/app/EditorLineStatus.java index 8420ddd4c..2696d7d41 100644 --- a/app/src/processing/app/EditorLineStatus.java +++ b/app/src/processing/app/EditorLineStatus.java @@ -1,3 +1,5 @@ +/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + /* Part of the Processing project - http://processing.org @@ -20,26 +22,21 @@ package processing.app; -import processing.app.helpers.OSUtils; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Font; -import java.awt.Graphics; -import java.awt.Image; +import java.awt.*; import java.awt.geom.Rectangle2D; +import java.util.Map; import javax.swing.JComponent; +import processing.app.helpers.OSUtils; import processing.app.helpers.PreferencesMap; -import processing.app.syntax.JEditTextArea; +import processing.app.syntax.SketchTextArea; + /** * Li'l status bar fella that shows the line number. */ -@SuppressWarnings("serial") public class EditorLineStatus extends JComponent { - JEditTextArea textarea; int start = -1, stop; Image resize; @@ -55,10 +52,8 @@ public class EditorLineStatus extends JComponent { String name = ""; String serialport = ""; - public EditorLineStatus(JEditTextArea textarea) { - this.textarea = textarea; - textarea.editorLineStatus = this; + public EditorLineStatus() { background = Theme.getColor("linestatus.bgcolor"); font = Theme.getFont("linestatus.font"); foreground = Theme.getColor("linestatus.color"); @@ -101,7 +96,7 @@ public class EditorLineStatus extends JComponent { setBoardName(boardPreferences.get("name")); else setBoardName("-"); - setSerialPort(Preferences.get("serial.port")); + setSerialPort(PreferencesData.get("serial.port")); } g.setColor(background); Dimension size = getSize(); diff --git a/app/src/processing/app/EditorListener.java b/app/src/processing/app/EditorListener.java index c2d2fe600..19e90b1c3 100644 --- a/app/src/processing/app/EditorListener.java +++ b/app/src/processing/app/EditorListener.java @@ -1,636 +1,83 @@ -/* -*- 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.Toolkit; +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; -import java.awt.*; -import java.awt.event.*; +import processing.app.syntax.SketchTextArea; - -/** - * 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 { +public class EditorListener implements KeyListener { + 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) { + + public EditorListener(Editor editor) { + super(); this.editor = editor; - this.textarea = textarea; - - // let him know that i'm leechin' - textarea.editorListener = this; - - applyPreferences(); } + + /** ctrl-alt on windows and linux, cmd-alt on mac os x */ + static final int CTRL_ALT = ActionEvent.ALT_MASK | Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(); + static final int CTRL_SHIFT = ActionEvent.SHIFT_MASK | Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(); + + static final int CTRL = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(); + - 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 + public void keyTyped(KeyEvent event) { char c = event.getKeyChar(); - int code = event.getKeyCode(); -// if (code == KeyEvent.VK_SHIFT) { -// editor.toolbar.setShiftPressed(true); -// } - - //System.out.println((int)c + " " + code + " " + event); - //System.out.println(); + if ((event.getModifiers() & KeyEvent.CTRL_MASK) != 0) { + // The char is not control code when CTRL key pressed? It should be a shortcut. + if (!Character.isISOControl(c)) { + event.consume(); + } + } + } + @Override + public void keyPressed(KeyEvent event) { + + SketchTextArea textarea = editor.getTextArea(); + + if (!textarea.isEditable()) return; + Sketch sketch = editor.getSketch(); + int code = event.getKeyCode(); + + // Navigation.. + if ((event.getModifiers() & CTRL) == CTRL && code == KeyEvent.VK_TAB) { + sketch.handleNextCode(); + } + + // Navigation.. + // FIXME: not working on LINUX !!! + if (((event.getModifiers() & CTRL_SHIFT) == CTRL_SHIFT)) { + if(code == KeyEvent.VK_TAB) + sketch.handlePrevCode(); + } + + // Navigation.. 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.CTRL_MASK) != 0) { - // Consume ctrl-m(carriage return) keypresses - if (code == KeyEvent.VK_M) { - event.consume(); // does nothing - return false; - } - - // The char is not control code when CTRL key pressed? It should be a shortcut. - if (!Character.isISOControl(c)) { - return false; - } - } - - 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 keyReleased(KeyEvent event) { -// if (code == KeyEvent.VK_SHIFT) { -// editor.toolbar.setShiftPressed(false); + +// if (event.isAltDown() && code == KeyEvent.VK_T) { +// int line = textarea.getCaretLineNumber(); +// textarea.setActiveLineRange(line, line + 3); // } -// } - - - public boolean keyTyped(KeyEvent event) { - char c = event.getKeyChar(); - - if ((event.getModifiers() & KeyEvent.CTRL_MASK) != 0) { - // The char is not control code when CTRL key pressed? It should be a shortcut. - if (!Character.isISOControl(c)) { - 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; + @Override + public void keyReleased(KeyEvent e) { + // TODO Auto-generated method stub + } - - /** - * 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++; - } - } - } - */ -} +} \ No newline at end of file diff --git a/app/src/processing/app/EditorStatus.java b/app/src/processing/app/EditorStatus.java index 1d90760f1..82abf3aa2 100644 --- a/app/src/processing/app/EditorStatus.java +++ b/app/src/processing/app/EditorStatus.java @@ -219,7 +219,7 @@ public class EditorStatus extends JPanel /*implements ActionListener*/ { public void unprogress() { - if (Preferences.getBoolean("editor.beep.compile")) { + if (PreferencesData.getBoolean("editor.beep.compile")) { Toolkit.getDefaultToolkit().beep(); } if (progressBar == null) return; @@ -464,10 +464,10 @@ public class EditorStatus extends JPanel /*implements ActionListener*/ { copyErrorButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { String message = ""; - message += _("Arduino: ") + BaseNoGui.VERSION_NAME + " (" + System.getProperty("os.name") + "), "; + message += _("Arduino: ") + BaseNoGui.VERSION_NAME_LONG + " (" + System.getProperty("os.name") + "), "; message += _("Board: ") + "\"" + Base.getBoardPreferences().get("name") + "\"\n\n"; message += editor.console.consoleTextPane.getText().trim(); - if ((Preferences.getBoolean("build.verbose")) == false) { + if ((PreferencesData.getBoolean("build.verbose")) == false) { message += "\n\n"; message += " " + _("This report would have more information with") + "\n"; message += " \"" + _("Show verbose output during compilation") + "\"\n"; diff --git a/app/src/processing/app/EditorToolbar.java b/app/src/processing/app/EditorToolbar.java index e33789b36..67edcdb79 100644 --- a/app/src/processing/app/EditorToolbar.java +++ b/app/src/processing/app/EditorToolbar.java @@ -321,7 +321,7 @@ public class EditorToolbar extends JComponent implements MouseInputListener, Key switch (sel) { case RUN: - editor.handleRun(false); + editor.handleRun(false, editor.presentHandler, editor.runHandler); break; // case STOP: diff --git a/app/src/processing/app/LastUndoableEditAwareUndoManager.java b/app/src/processing/app/LastUndoableEditAwareUndoManager.java index 0cd678a93..736be42d3 100644 --- a/app/src/processing/app/LastUndoableEditAwareUndoManager.java +++ b/app/src/processing/app/LastUndoableEditAwareUndoManager.java @@ -2,31 +2,36 @@ package processing.app; import javax.swing.undo.CannotRedoException; import javax.swing.undo.CannotUndoException; -import javax.swing.undo.UndoManager; -import javax.swing.undo.UndoableEdit; -@SuppressWarnings("serial") -public class LastUndoableEditAwareUndoManager extends UndoManager { +import org.fife.ui.rtextarea.RUndoManager; - private UndoableEdit lastUndoableEdit; +import processing.app.syntax.SketchTextArea; - public LastUndoableEditAwareUndoManager() { - this.lastUndoableEdit = null; +public class LastUndoableEditAwareUndoManager extends RUndoManager { + + private Editor editor; + + public LastUndoableEditAwareUndoManager(SketchTextArea textarea, Editor editor) { + super(textarea); + this.editor = editor; } @Override public synchronized void undo() throws CannotUndoException { - lastUndoableEdit = super.editToBeUndone(); super.undo(); } @Override public synchronized void redo() throws CannotRedoException { - lastUndoableEdit = super.editToBeRedone(); super.redo(); } - - public UndoableEdit getLastUndoableEdit() { - return lastUndoableEdit; + + @Override + public void updateActions() { + super.updateActions(); + editor.undoAction.updateUndoState(); + editor.redoAction.updateRedoState(); } + + } diff --git a/app/src/processing/app/Preferences.java b/app/src/processing/app/Preferences.java index e0910c343..6f76d6e4f 100644 --- a/app/src/processing/app/Preferences.java +++ b/app/src/processing/app/Preferences.java @@ -21,58 +21,30 @@ package processing.app; -import static processing.app.I18n._; - -import java.awt.Color; -import java.awt.Container; -import java.awt.Dimension; -import java.awt.Font; -import java.awt.Insets; -import java.awt.SystemColor; -import java.awt.Toolkit; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.KeyAdapter; -import java.awt.event.KeyEvent; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; -import java.io.File; - -import javax.swing.Box; -import javax.swing.JButton; -import javax.swing.JCheckBox; -import javax.swing.JComboBox; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JTextField; -import javax.swing.KeyStroke; - -import processing.app.helpers.FileUtils; -import processing.app.helpers.OSUtils; import processing.app.helpers.PreferencesHelper; import processing.app.helpers.PreferencesMap; -import processing.app.legacy.PApplet; + +import java.awt.*; +import java.io.File; /** * 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 @@ -85,114 +57,12 @@ import processing.app.legacy.PApplet; */ public class Preferences { - static final String PREFS_FILE = PreferencesData.PREFS_FILE; - - class Language { - Language(String _name, String _originalName, String _isoCode) { - name = _name; - originalName = _originalName; - isoCode = _isoCode; - } - - public String toString() { - if (originalName.length() == 0) - return name; - return originalName + " (" + name + ")"; - }; - - String name; - String originalName; - String isoCode; - } - - Language languages[] = { - new Language(_("System Default"), "", ""), - new Language(_("Albanian"), "shqip", "sq"), - new Language(_("Arabic"), "العربية", "ar"), - new Language(_("Aragonese"), "Aragonés", "an"), - new Language(_("Belarusian"), "БеларуÑÐºÐ°Ñ Ð¼Ð¾Ð²Ð°", "be"), - new Language(_("Bulgarian"), "българÑки", "bg"), - new Language(_("Catalan"), "Català", "ca"), - new Language(_("Chinese Simplified"), "简体中文", "zh_CN"), - new Language(_("Chinese Traditional"), "ç¹é«”中文", "zh_TW"), - new Language(_("Croatian"), "Hrvatski", "hr_HR"), - new Language(_("Czech (Czech Republic)"), "Äeský (Czech Republic)", "cs_CZ"), - new Language(_("Danish (Denmark)"), "Dansk (Denmark)", "da_DK"), - new Language(_("Dutch"), "Nederlands", "nl"), - new Language(_("English"), "English", "en"), - new Language(_("English (United Kingdom)"), "English (United Kingdom)", "en_GB"), - new Language(_("Estonian"), "Eesti", "et"), - new Language(_("Estonian (Estonia)"), "Eesti keel", "et_EE"), - new Language(_("Filipino"), "Pilipino", "fil"), - new Language(_("Finnish"), "Suomi", "fi"), - new Language(_("French"), "Français", "fr"), - new Language(_("Canadian French"), "Canadienne-français", "fr_CA"), - new Language(_("Galician"), "Galego", "gl"), - new Language(_("Georgian"), "სáƒáƒ¥áƒáƒ áƒ—ველáƒáƒ¡", "ka_GE"), - new Language(_("German"), "Deutsch", "de_DE"), - new Language(_("Greek"), "ελληνικά", "el_GR"), - new Language(_("Hebrew"), "עברית", "he"), - new Language(_("Hindi"), "हिंदी", "hi"), - new Language(_("Hungarian"), "Magyar", "hu"), - new Language(_("Indonesian"), "Bahasa Indonesia", "id"), - new Language(_("Italian"), "Italiano", "it_IT"), - new Language(_("Japanese"), "日本語", "ja_JP"), - new Language(_("Korean"), "한국어", "ko_KR"), - new Language(_("Latvian"), "LatvieÅ¡u", "lv_LV"), - new Language(_("Lithuaninan"), "Lietuvių Kalba", "lt_LT"), - new Language(_("Norwegian BokmÃ¥l"), "Norsk bokmÃ¥l", "nb_NO"), - new Language(_("Persian"), "ÙØ§Ø±Ø³ÛŒ", "fa"), - new Language(_("Polish"), "JÄ™zyk Polski", "pl"), - new Language(_("Portuguese (Brazil)"), "Português (Brazil)", "pt_BR"), - new Language(_("Portuguese (Portugal)"), "Português (Portugal)", "pt_PT"), - new Language(_("Romanian"), "Română", "ro"), - new Language(_("Russian"), "РуÑÑкий", "ru"), - new Language(_("Slovenian"), "SlovenÅ¡Äina", "sl_SI"), - new Language(_("Spanish"), "Español", "es"), - new Language(_("Swedish"), "Svenska", "sv"), - new Language(_("Tamil"), "தமிழà¯", "ta"), - new Language(_("Turkish"), "Türk", "tr"), - new Language(_("Ukrainian"), "УкраїнÑький", "uk"), - new Language(_("Vietnamese"), "Tiếng Việt", "vi"), - }; - - // Incomplete languages - Language missingLanguages[] = { - new Language(_("Afrikaans"), "Afrikaans", "af"), - new Language(_("Armenian"), "Õ€Õ¡ÕµÕ¥Ö€Õ¥Õ¶", "hy"), - new Language(_("Asturian"), "Asturianu", "ast"), - new Language(_("Basque"), "Euskara", "eu"), - new Language(_("Bengali (India)"), "বাংলা (India)", "bn_IN"), - new Language(_("Bosnian"), "Bosanski", "bs"), - new Language(_("Burmese (Myanmar)"), "ဗမာစကား", "my_MM"), - new Language(_("Chinese (China)"), "", "zh_CN"), - new Language(_("Chinese (Hong Kong)"), "", "zh_HK"), - new Language(_("Chinese (Taiwan)"), "", "zh_TW"), - new Language(_("Chinese (Taiwan) (Big5)"), "", "zh_TW.Big5"), - new Language(_("Czech"), "Äeský", "cs"), - new Language(_("Danish"), "Dansk", "da"), - new Language(_("Dutch (Netherlands)"), "Nederlands", "nl_NL"), - new Language(_("Galician (Spain)"), "Galego (Spain)", "gl_ES"), - new Language(_("Nepali"), "नेपाली", "ne"), - new Language(_("N'Ko"), "ß’ßžß", "nqo"), - new Language(_("Marathi"), "मराठी", "mr"), - new Language(_("Malay (Malaysia)"), "بهاس ملايو (Malaysia)", "ms_MY"), - new Language(_("Norwegian"), "Norsk", "no"), - new Language(_("Norwegian Nynorsk"), "Norsk Nynorsk", "nn"), - new Language(_("Portugese"), "Português", "pt"), - new Language(_("Persian (Iran)"), "ÙØ§Ø±Ø³ÛŒ (Iran)", "fa_IR"), - new Language(_("Slovak"), "SlovenÄina", "sk"), - new Language(_("Swahili"), "ÙƒÙØ³ÙˆÙŽÙ‡ÙÙ„", "sw"), - new Language(_("Talossan"), "Talossan", "tzl"), - new Language(_("Urdu (Pakistan)"), "اردو (Pakistan)", "ur_PK"), - new Language(_("Western Frisian"), "Western Frisian", "fy"), - }; /** * 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; + static public int BUTTON_WIDTH = 80; /** * Standardized button height. Mac OS X 10.3 (Java 1.4) wants 29, @@ -205,549 +75,85 @@ public class Preferences { // value for the size bars, buttons, etc - static final int GRID_SIZE = 33; + 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 verboseCompilationBox; - JCheckBox verboseUploadBox; - JCheckBox displayLineNumbersBox; - JCheckBox verifyUploadBox; - JCheckBox externalEditorBox; - JCheckBox memoryOverrideBox; - JTextField memoryField; - JCheckBox checkUpdatesBox; - JTextField fontSizeField; - JCheckBox updateExtensionBox; - JCheckBox autoAssociateBox; - JComboBox comboLanguage; - JCheckBox saveVerifyUploadBox; - - - // the calling editor, so updates can be applied - - Editor editor; - + static final int GUI_SMALL = 6; static protected void init(File file) { - - PreferencesData.init(file); + PreferencesData.init(file); // other things that have to be set explicitly for the defaults PreferencesHelper.putColor(PreferencesData.prefs, "run.window.bgcolor", SystemColor.control); } - - 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; - - - // 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(I18n.PROMPT_BROWSE); - button.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - File dflt = new File(sketchbookLocationField.getText()); - File file = - Base.selectFolder(_("Select new sketchbook location"), dflt, dialog); - if (file != null) { - String path = file.getAbsolutePath(); - if (Base.getPortableFolder() != null) { - path = FileUtils.relativePath(Base.getPortableFolder().toString(), path); - if (path == null) { - path = Base.getPortableSketchbookFolder(); - } - } - sketchbookLocationField.setText(path); - } - } - }); - pain.add(button); - d2 = button.getPreferredSize(); - - // take max height of all components to vertically align em - vmax = Math.max(d.height, d2.height); - sketchbookLocationField.setBounds(left, top + (vmax-d.height)/2, - d.width, d.height); - h = left + d.width + GUI_SMALL; - 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; - - - // Preferred language: [ ] (requires restart of Arduino) - Container box = Box.createHorizontalBox(); - label = new JLabel(_("Editor language: ")); - box.add(label); - comboLanguage = new JComboBox(languages); - String currentLanguage = PreferencesData.get("editor.languages.current"); - for (Language language : languages) { - if (language.isoCode.equals(currentLanguage)) - comboLanguage.setSelectedItem(language); - } - box.add(comboLanguage); - label = new JLabel(_(" (requires restart of Arduino)")); - box.add(label); - pain.add(box); - d = box.getPreferredSize(); - box.setForeground(Color.gray); - box.setBounds(left, top, d.width, d.height); - right = Math.max(right, left + d.width); - top += d.height + GUI_BETWEEN; - - // Editor font size [ ] - - 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 Arduino)")); - 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; - - - // Show verbose output during: [ ] compilation [ ] upload - - box = Box.createHorizontalBox(); - label = new JLabel(_("Show verbose output during: ")); - box.add(label); - verboseCompilationBox = new JCheckBox(_("compilation ")); - box.add(verboseCompilationBox); - verboseUploadBox = new JCheckBox(_("upload")); - box.add(verboseUploadBox); - pain.add(box); - d = box.getPreferredSize(); - box.setBounds(left, top, d.width, d.height); - top += d.height + GUI_BETWEEN; - - // [ ] Display line numbers - - displayLineNumbersBox = new JCheckBox(_("Display line numbers")); - pain.add(displayLineNumbersBox); - d = displayLineNumbersBox.getPreferredSize(); - displayLineNumbersBox.setBounds(left, top, d.width + 10, d.height); - right = Math.max(right, left + d.width); - top += d.height + GUI_BETWEEN; - - // [ ] Verify code after upload - - verifyUploadBox = new JCheckBox(_("Verify code after upload")); - pain.add(verifyUploadBox); - d = verifyUploadBox.getPreferredSize(); - verifyUploadBox.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; - - // [ ] Update sketch files to new extension on save (.pde -> .ino) - - updateExtensionBox = new JCheckBox(_("Update sketch files to new extension on save (.pde -> .ino)")); - pain.add(updateExtensionBox); - d = updateExtensionBox.getPreferredSize(); - updateExtensionBox.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 (OSUtils.isWindows()) { - autoAssociateBox = - new JCheckBox(_("Automatically associate .ino files with Arduino")); - 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; - - // If using portable mode, it's bad manner to change PC setting. - if (Base.getPortableFolder() != null) - autoAssociateBox.setEnabled(false); - } - - // [ ] save when verifying or uploading - - saveVerifyUploadBox = new JCheckBox(_("Save when verifying or uploading")); - pain.add(saveVerifyUploadBox); - d = saveVerifyUploadBox.getPreferredSize(); - saveVerifyUploadBox.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(PreferencesData.preferencesFile.getAbsolutePath()); - final JLabel clickable = label; - label.addMouseListener(new MouseAdapter() { - public void mousePressed(MouseEvent e) { - Base.openFolder(PreferencesData.preferencesFile.getParentFile()); - } - - public void mouseEntered(MouseEvent e) { - clickable.setForeground(new Color(0, 0, 140)); - } - - public void mouseExited(MouseEvent e) { - clickable.setForeground(Color.BLACK); - } - }); - 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 Arduino 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(I18n.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(I18n.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; - - - // 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(); - } - } - }); - } - - - // ................................................................. - - - /** - * 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 - PreferencesData.setBoolean("build.verbose", verboseCompilationBox.isSelected()); - PreferencesData.setBoolean("upload.verbose", verboseUploadBox.isSelected()); - PreferencesData.setBoolean("editor.linenumbers", displayLineNumbersBox.isSelected()); - PreferencesData.setBoolean("upload.verify", verifyUploadBox.isSelected()); - PreferencesData.setBoolean("editor.save_on_verify", saveVerifyUploadBox.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 = PreferencesData.get("sketchbook.path"); - String newPath = sketchbookLocationField.getText(); - if (newPath.isEmpty()) { - if (Base.getPortableFolder() == null) - newPath = editor.base.getDefaultSketchbookFolderOrPromptForIt().toString(); - else - newPath = Base.getPortableSketchbookFolder(); - } - if (!newPath.equals(oldPath)) { - editor.base.rebuildSketchbookMenus(); - PreferencesData.set("sketchbook.path", newPath); - } - - PreferencesData.setBoolean("editor.external", externalEditorBox.isSelected()); - PreferencesData.setBoolean("update.check", checkUpdatesBox.isSelected()); - PreferencesData.setBoolean("editor.save_on_verify", saveVerifyUploadBox.isSelected()); - - /* - // 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(PreferencesData.get("editor.font"), ','); - pieces[2] = String.valueOf(newSize); - PreferencesData.set("editor.font", PApplet.join(pieces, ',')); - - } catch (Exception e) { - System.err.println(I18n.format(_("ignoring invalid font size {0}"), newSizeText)); - } - - if (autoAssociateBox != null) { - PreferencesData.setBoolean("platform.auto_file_type_associations", - autoAssociateBox.isSelected()); - } - - PreferencesData.setBoolean("editor.update_extension", updateExtensionBox.isSelected()); - - // adds the selected language to the preferences file - Language newLanguage = (Language) comboLanguage.getSelectedItem(); - PreferencesData.set("editor.languages.current", newLanguage.isoCode); - - editor.applyPreferences(); - } - - - protected void showFrame(Editor editor) { - this.editor = editor; - - // set all settings entry boxes to their actual status - verboseCompilationBox.setSelected(PreferencesData.getBoolean("build.verbose")); - verboseUploadBox.setSelected(PreferencesData.getBoolean("upload.verbose")); - displayLineNumbersBox.setSelected(PreferencesData.getBoolean("editor.linenumbers")); - verifyUploadBox.setSelected(PreferencesData.getBoolean("upload.verify")); - - //closingLastQuitsBox. - // setSelected(getBoolean("sketchbook.closing_last_window_quits")); - //sketchPromptBox. - // setSelected(getBoolean("sketchbook.prompt")); - //sketchCleanBox. - // setSelected(getBoolean("sketchbook.auto_clean")); - - sketchbookLocationField. - setText(PreferencesData.get("sketchbook.path")); - externalEditorBox. - setSelected(PreferencesData.getBoolean("editor.external")); - checkUpdatesBox. - setSelected(PreferencesData.getBoolean("update.check")); - saveVerifyUploadBox. - setSelected(PreferencesData.getBoolean("editor.save_on_verify")); - - if (autoAssociateBox != null) { - autoAssociateBox. - setSelected(PreferencesData.getBoolean("platform.auto_file_type_associations")); - } - - updateExtensionBox.setSelected(PreferencesData.get("editor.update_extension") == null || - PreferencesData.getBoolean("editor.update_extension")); - - dialog.setVisible(true); - } - - - static protected void save() { + @Deprecated + protected static void save() { PreferencesData.save(); } - - // ................................................................. - - static public String get(String attribute) { + @Deprecated + public static String get(String attribute) { return PreferencesData.get(attribute); } - static public String get(String attribute, String defaultValue) { + @Deprecated + public static String get(String attribute, String defaultValue) { return PreferencesData.get(attribute, defaultValue); } + @Deprecated public static boolean has(String key) { return PreferencesData.has(key); } + @Deprecated public static void remove(String key) { PreferencesData.remove(key); } - - static public void set(String attribute, String value) { + @Deprecated + public static void set(String attribute, String value) { PreferencesData.set(attribute, value); } - - static public boolean getBoolean(String attribute) { + @Deprecated + public static boolean getBoolean(String attribute) { return PreferencesData.getBoolean(attribute); } - - static public void setBoolean(String attribute, boolean value) { + @Deprecated + public static void setBoolean(String attribute, boolean value) { PreferencesData.setBoolean(attribute, value); } - - static public int getInteger(String attribute) { + @Deprecated + public static int getInteger(String attribute) { return PreferencesData.getInteger(attribute); } + @Deprecated + public static int getInteger(String attribute, int defaultValue) { + return PreferencesData.getInteger(attribute, defaultValue); + } - static public void setInteger(String key, int value) { + @Deprecated + public static void setInteger(String key, int value) { PreferencesData.setInteger(key, value); } - - static public Font getFont(String attr) { - Font font = PreferencesHelper.getFont(PreferencesData.prefs, attr); - if (font == null) { - String value = PreferencesData.defaults.get(attr); - PreferencesData.prefs.put(attr, value); - font = PreferencesHelper.getFont(PreferencesData.prefs, attr); - } - return font; - } - - // get a copy of the Preferences - static public PreferencesMap getMap() - { + @Deprecated + public static PreferencesMap getMap() { return PreferencesData.getMap(); } - // Decide wether changed preferences will be saved. When value is - // false, Preferences.save becomes a no-op. - static public void setDoSave(boolean value) - { + @Deprecated + public static void setDoSave(boolean value) { PreferencesData.setDoSave(value); } + } diff --git a/app/src/processing/app/PresentMode.java b/app/src/processing/app/PresentMode.java index 34cba7928..f9bc568de 100644 --- a/app/src/processing/app/PresentMode.java +++ b/app/src/processing/app/PresentMode.java @@ -74,14 +74,14 @@ public class PresentMode { public void actionPerformed(ActionEvent e) { int index = selector.getSelectedIndex(); //device = devices[index]; - Preferences.setInteger("run.present.display", index + 1); + PreferencesData.setInteger("run.present.display", index + 1); } }); } static public JComboBox getSelector() { - int deviceIndex = Preferences.getInteger("run.present.display") - 1; + int deviceIndex = PreferencesData.getInteger("run.present.display") - 1; selector.setSelectedIndex(deviceIndex); return selector; } diff --git a/app/src/processing/app/SerialMonitor.java b/app/src/processing/app/SerialMonitor.java index 122e3323d..9f48f82cb 100644 --- a/app/src/processing/app/SerialMonitor.java +++ b/app/src/processing/app/SerialMonitor.java @@ -39,14 +39,14 @@ public class SerialMonitor extends AbstractMonitor { this.port = port.getAddress(); - serialRate = Preferences.getInteger("serial.debug_rate"); + serialRate = PreferencesData.getInteger("serial.debug_rate"); serialRates.setSelectedItem(serialRate + " " + _("baud")); onSerialRateChange(new ActionListener() { public void actionPerformed(ActionEvent event) { String wholeString = (String) serialRates.getSelectedItem(); String rateString = wholeString.substring(0, wholeString.indexOf(' ')); serialRate = Integer.parseInt(rateString); - Preferences.set("serial.debug_rate", rateString); + PreferencesData.set("serial.debug_rate", rateString); try { close(); Thread.sleep(100); // Wait for serial port to properly close @@ -80,9 +80,9 @@ public class SerialMonitor extends AbstractMonitor { s += "\r\n"; break; } - if ("".equals(s) && lineEndings.getSelectedIndex() == 0 && !Preferences.has("runtime.line.ending.alert.notified")) { + if ("".equals(s) && lineEndings.getSelectedIndex() == 0 && !PreferencesData.has("runtime.line.ending.alert.notified")) { noLineEndingAlert.setForeground(Color.RED); - Preferences.set("runtime.line.ending.alert.notified", "true"); + PreferencesData.set("runtime.line.ending.alert.notified", "true"); } serial.write(s); } @@ -103,7 +103,7 @@ public class SerialMonitor extends AbstractMonitor { if (serial != null) { int[] location = getPlacement(); String locationStr = PApplet.join(PApplet.str(location), ","); - Preferences.set("last.serial.location", locationStr); + PreferencesData.set("last.serial.location", locationStr); textArea.setText(""); serial.dispose(); serial = null; diff --git a/app/src/processing/app/Sketch.java b/app/src/processing/app/Sketch.java index 2f142d01b..74ca35733 100644 --- a/app/src/processing/app/Sketch.java +++ b/app/src/processing/app/Sketch.java @@ -23,18 +23,15 @@ package processing.app; -import cc.arduino.packages.BoardPort; import cc.arduino.packages.Uploader; -import cc.arduino.view.*; import processing.app.debug.Compiler; import processing.app.debug.Compiler.ProgressListener; import processing.app.debug.RunnerException; -import processing.app.debug.TargetBoard; import processing.app.forms.PasswordAuthorizationDialog; import processing.app.helpers.OSUtils; -import processing.app.helpers.PreferencesMap; import processing.app.helpers.PreferencesMapException; -import processing.app.packages.Library; +import processing.app.packages.UserLibrary; +import static processing.app.I18n._; import javax.swing.*; import java.awt.*; @@ -45,8 +42,6 @@ import java.util.Arrays; import java.util.LinkedList; import java.util.List; -import static processing.app.I18n._; - /** * Stores information about files in the current sketch @@ -117,7 +112,7 @@ public class Sketch { for (SketchCode code : data.getCodes()) { if (code.getMetadata() == null) - code.setMetadata(new SketchCodeDocument(code)); + code.setMetadata(new SketchCodeDocument(this, code)); } // set the main file to be the current tab @@ -414,7 +409,7 @@ public class Sketch { return; } ensureExistence(); - data.addCode((new SketchCodeDocument(newFile)).getCode()); + data.addCode((new SketchCodeDocument(this, newFile)).getCode()); } // sort the entries @@ -580,7 +575,7 @@ public class Sketch { }); if (pdeFiles != null && pdeFiles.length > 0) { - if (Preferences.get("editor.update_extension") == null) { + if (PreferencesData.get("editor.update_extension") == null) { Object[] options = { _("OK"), _("Cancel") }; int result = JOptionPane.showOptionDialog(editor, _("In Arduino 1.0, the default file extension has changed\n" + @@ -599,10 +594,10 @@ public class Sketch { if (result != JOptionPane.OK_OPTION) return false; // save cancelled - Preferences.setBoolean("editor.update_extension", true); + PreferencesData.setBoolean("editor.update_extension", true); } - if (Preferences.getBoolean("editor.update_extension")) { + if (PreferencesData.getBoolean("editor.update_extension")) { // Do rename of all .pde files to new .ino extension for (File pdeFile : pdeFiles) renameCodeToInoExtension(pdeFile); @@ -806,7 +801,7 @@ public class Sketch { if (result) { editor.statusNotice(_("One file added to the sketch.")); - Preferences.set("last.folder", sourceFile.getAbsolutePath()); + PreferencesData.set("last.folder", sourceFile.getAbsolutePath()); } } @@ -910,7 +905,7 @@ public class Sketch { } if (codeExtension != null) { - SketchCode newCode = (new SketchCodeDocument(destFile)).getCode(); + SketchCode newCode = (new SketchCodeDocument(this, destFile)).getCode(); if (replacement) { data.replaceCode(newCode); @@ -938,7 +933,7 @@ public class Sketch { } - public void importLibrary(Library lib) throws IOException { + public void importLibrary(UserLibrary lib) throws IOException { importLibrary(lib.getSrcFolder()); } @@ -1064,7 +1059,7 @@ public class Sketch { // if an external editor is being used, need to grab the // latest version of the code from the file. - if (Preferences.getBoolean("editor.external")) { + if (PreferencesData.getBoolean("editor.external")) { // history gets screwed by the open.. //String historySaved = history.lastRecorded; //handleOpen(sketch); @@ -1138,8 +1133,8 @@ public class Sketch { * @return null if compilation failed, main class name if not * @throws RunnerException */ - public String build(boolean verbose) throws RunnerException, PreferencesMapException { - return build(tempBuildFolder.getAbsolutePath(), verbose); + public String build(boolean verbose, boolean save) throws RunnerException, PreferencesMapException { + return build(tempBuildFolder.getAbsolutePath(), verbose, save); } /** @@ -1151,9 +1146,7 @@ public class Sketch { * * @return null if compilation failed, main class name if not */ - public String build(String buildPath, boolean verbose) throws RunnerException, PreferencesMapException { - useOriginalVidPidIfUncertified(); - + public String build(String buildPath, boolean verbose, boolean save) throws RunnerException, PreferencesMapException { // run the preprocessor editor.status.progressUpdate(20); @@ -1166,7 +1159,7 @@ public class Sketch { } }; - return Compiler.build(data, buildPath, tempBuildFolder, pl, verbose); + return Compiler.build(data, buildPath, tempBuildFolder, pl, verbose, save); } protected boolean exportApplet(boolean usingProgrammer) throws Exception { @@ -1184,7 +1177,7 @@ public class Sketch { // build the sketch editor.status.progressNotice(_("Compiling sketch...")); - String foundName = build(appletPath, false); + String foundName = build(appletPath, false, false); // (already reported) error during export, exit this function if (foundName == null) return false; @@ -1203,45 +1196,13 @@ public class Sketch { return success; } - private void useOriginalVidPidIfUncertified() { - BoardPort boardPort = BaseNoGui.getDiscoveryManager().find(PreferencesData.get("serial.port")); - if (boardPort == null) { - return; - } - TargetBoard targetBoard = BaseNoGui.getTargetBoard(); - if (targetBoard == null) { - return; - } - PreferencesMap boardPreferences = targetBoard.getPreferences(); - if (boardPreferences.containsKey("build.vid") && boardPreferences.containsKey("build.pid")) { - if (!boardPreferences.containsKey("backup.build.vid")) { - boardPreferences.put("backup.build.vid", boardPreferences.get("build.vid")); - boardPreferences.put("backup.build.pid", boardPreferences.get("build.pid")); - } - - if (boardPort.getPrefs().get("warning") != null) { - boardPreferences.put("build.vid", boardPort.getPrefs().get("vid")); - boardPreferences.put("build.pid", boardPort.getPrefs().get("pid")); - } else { - boardPreferences.put("build.vid", boardPreferences.get("backup.build.vid")); - boardPreferences.put("build.pid", boardPreferences.get("backup.build.pid")); - } - } - - if (boardPort.getPrefs().get("warning") != null && !Preferences.getBoolean("uncertifiedBoardWarning_dontShowMeAgain")) { - SwingUtilities.invokeLater(new ShowUncertifiedBoardWarning(editor)); - } - - - } - protected boolean upload(String buildPath, String suggestedClassName, boolean usingProgrammer) throws Exception { Uploader uploader = Compiler.getUploaderByPreferences(false); boolean success = false; do { - if (uploader.requiresAuthorization() && !Preferences.has(uploader.getAuthorizationKey())) { + if (uploader.requiresAuthorization() && !PreferencesData.has(uploader.getAuthorizationKey())) { PasswordAuthorizationDialog dialog = new PasswordAuthorizationDialog(editor, _("Type board password to upload a new sketch")); dialog.setLocationRelativeTo(editor); dialog.setVisible(true); @@ -1251,7 +1212,7 @@ public class Sketch { return false; } - Preferences.set(uploader.getAuthorizationKey(), dialog.getPassword()); + PreferencesData.set(uploader.getAuthorizationKey(), dialog.getPassword()); } List warningsAccumulator = new LinkedList(); @@ -1259,7 +1220,7 @@ public class Sketch { success = Compiler.upload(data, uploader, buildPath, suggestedClassName, usingProgrammer, false, warningsAccumulator); } finally { if (uploader.requiresAuthorization() && !success) { - Preferences.remove(uploader.getAuthorizationKey()); + PreferencesData.remove(uploader.getAuthorizationKey()); } } diff --git a/app/src/processing/app/SketchCodeDocument.java b/app/src/processing/app/SketchCodeDocument.java index 857a270ab..681f0af91 100644 --- a/app/src/processing/app/SketchCodeDocument.java +++ b/app/src/processing/app/SketchCodeDocument.java @@ -2,37 +2,43 @@ package processing.app; import java.io.File; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; import javax.swing.text.Document; +import javax.swing.undo.UndoManager; -public class SketchCodeDocument{ +public class SketchCodeDocument implements DocumentListener{ private SketchCode code; + private Sketch sketch; 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 LastUndoableEditAwareUndoManager undo = new LastUndoableEditAwareUndoManager(); + private UndoManager undo; // saved positions from last time this tab was used private int selectionStart; private int selectionStop; private int scrollPosition; - public SketchCodeDocument(SketchCode code) { + public SketchCodeDocument(Sketch sketch, SketchCode code) { this.code = code; + this.sketch = sketch; this.code.setMetadata(this); } - public SketchCodeDocument(File file) { + public SketchCodeDocument(Sketch sketch, File file) { this.code = new SketchCode(file, this); + this.sketch = sketch; } - public LastUndoableEditAwareUndoManager getUndo() { + public UndoManager getUndo() { return undo; } - public void setUndo(LastUndoableEditAwareUndoManager undo) { + public void setUndo(UndoManager undo) { this.undo = undo; } @@ -74,6 +80,24 @@ public class SketchCodeDocument{ public void setDocument(Document document) { this.document = document; + document.addDocumentListener(this); } + @Override + public void insertUpdate(DocumentEvent e) { + if(!code.isModified()) sketch.setModified(true); + } + + + @Override + public void removeUpdate(DocumentEvent e) { + if(!code.isModified()) sketch.setModified(true); + } + + @Override + public void changedUpdate(DocumentEvent e) { + // Callback for when styles in the current document change. + // This method is never called. + } + } diff --git a/app/src/processing/app/Theme.java b/app/src/processing/app/Theme.java index 7f23d3c46..841880d9b 100644 --- a/app/src/processing/app/Theme.java +++ b/app/src/processing/app/Theme.java @@ -21,15 +21,19 @@ package processing.app; -import static processing.app.I18n._; - -import java.awt.Color; -import java.awt.Font; -import java.awt.SystemColor; - +import processing.app.helpers.OSUtils; import processing.app.helpers.PreferencesHelper; import processing.app.helpers.PreferencesMap; -import processing.app.syntax.SyntaxStyle; + +import javax.swing.text.StyleContext; +import java.awt.*; +import java.awt.font.TextAttribute; +import java.io.File; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Map; + +import static processing.app.I18n._; /** * Storage class for theme settings. This was separated from the Preferences @@ -38,17 +42,21 @@ import processing.app.syntax.SyntaxStyle; */ public class Theme { - /** Copy of the defaults in case the user mangles a preference. */ + /** + * Copy of the defaults in case the user mangles a preference. + */ static PreferencesMap defaults; - /** Table of attributes/values for the theme. */ + /** + * Table of attributes/values for the theme. + */ static PreferencesMap table = new PreferencesMap(); static protected void init() { try { - table.load(Base.getLibStream("theme/theme.txt")); + table.load(new File(BaseNoGui.getContentFile("lib"), "theme/theme.txt")); } catch (Exception te) { Base.showError(null, _("Could not read color theme settings.\n" + - "You'll need to reinstall Arduino."), te); + "You'll need to reinstall Arduino."), te); } // other things that have to be set explicitly for the defaults @@ -104,7 +112,41 @@ public class Theme { return font; } - static public SyntaxStyle getStyle(String what) { + /** + * Returns the default font for text areas. + * + * @return The default font. + */ + public static final Font getDefaultFont() { + + // Use StyleContext to get a composite font for better Asian language + // support; see Sun bug S282887. + StyleContext sc = StyleContext.getDefaultStyleContext(); + Font font = null; + + if (OSUtils.isMacOS()) { + // Snow Leopard (1.6) uses Menlo as default monospaced font, + // pre-Snow Leopard used Monaco. + font = sc.getFont("Menlo", Font.PLAIN, 12); + if (!"Menlo".equals(font.getFamily())) { + font = sc.getFont("Monaco", Font.PLAIN, 12); + if (!"Monaco".equals(font.getFamily())) { // Shouldn't happen + font = sc.getFont("Monospaced", Font.PLAIN, 13); + } + } + } else { + // Consolas added in Vista, used by VS2010+. + font = sc.getFont("Consolas", Font.PLAIN, 13); + if (!"Consolas".equals(font.getFamily())) { + font = sc.getFont("Monospaced", Font.PLAIN, 13); + } + } + + //System.out.println(font.getFamily() + ", " + font.getName()); + return font; + } + + public static Map getStyledFont(String what, Font font) { String split[] = get("editor." + what + ".style").split(","); Color color = PreferencesHelper.parseColor(split[0]); @@ -114,6 +156,18 @@ public class Theme { boolean italic = style.contains("italic"); boolean underlined = style.contains("underlined"); - return new SyntaxStyle(color, italic, bold, underlined); + Font styledFont = new Font(font.getFamily(), (bold ? Font.BOLD : 0) | (italic ? Font.ITALIC : 0), font.getSize()); + if (underlined) { + Map attr = new Hashtable(); + attr.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON); + styledFont = styledFont.deriveFont(attr); + } + + Map result = new HashMap(); + result.put("color", color); + result.put("font", styledFont); + + return result; } + } diff --git a/app/src/processing/app/UpdateCheck.java b/app/src/processing/app/UpdateCheck.java index 5e063bc6c..b3b48dfef 100644 --- a/app/src/processing/app/UpdateCheck.java +++ b/app/src/processing/app/UpdateCheck.java @@ -22,16 +22,16 @@ package processing.app; +import processing.app.legacy.PApplet; + +import javax.swing.*; import java.io.BufferedReader; -import java.io.InputStream; +import java.io.IOException; import java.io.InputStreamReader; import java.net.URL; import java.net.URLEncoder; import java.util.Random; -import javax.swing.JOptionPane; - -import processing.app.legacy.PApplet; import static processing.app.I18n._; @@ -69,11 +69,11 @@ public class UpdateCheck implements Runnable { Random r = new Random(); long id = r.nextLong(); - String idString = Preferences.get("update.id"); + String idString = PreferencesData.get("update.id"); if (idString != null) { id = Long.parseLong(idString); } else { - Preferences.set("update.id", String.valueOf(id)); + PreferencesData.set("update.id", String.valueOf(id)); } try { @@ -88,7 +88,7 @@ public class UpdateCheck implements Runnable { int latest = readInt(downloadURL + "?" + info); - String lastString = Preferences.get("update.last"); + String lastString = PreferencesData.get("update.last"); long now = System.currentTimeMillis(); if (lastString != null) { long when = Long.parseLong(lastString); @@ -97,7 +97,7 @@ public class UpdateCheck implements Runnable { return; } } - Preferences.set("update.last", String.valueOf(now)); + PreferencesData.set("update.last", String.valueOf(now)); String prompt = _("A new version of Arduino is available,\n" + @@ -126,11 +126,16 @@ public class UpdateCheck implements Runnable { } - protected int readInt(String filename) throws Exception { + protected int readInt(String filename) throws IOException { URL url = new URL(filename); - InputStream stream = url.openStream(); - InputStreamReader isr = new InputStreamReader(stream); - BufferedReader reader = new BufferedReader(isr); - return Integer.parseInt(reader.readLine()); + BufferedReader reader = null; + try { + reader = new BufferedReader(new InputStreamReader(url.openStream())); + return Integer.parseInt(reader.readLine()); + } finally { + if (reader != null) { + reader.close(); + } + } } } diff --git a/app/src/processing/app/debug/TargetPackageStub.java b/app/src/processing/app/debug/TargetPackageStub.java new file mode 100644 index 000000000..d564a9e4e --- /dev/null +++ b/app/src/processing/app/debug/TargetPackageStub.java @@ -0,0 +1,38 @@ +package processing.app.debug; + +import java.util.Collection; +import java.util.Map; + +public class TargetPackageStub implements TargetPackage { + + private final String id; + + public TargetPackageStub(String id) { + this.id = id; + } + + @Override + public String getId() { + return id; + } + + @Override + public Map getPlatforms() { + return null; + } + + @Override + public Collection platforms() { + return null; + } + + @Override + public TargetPlatform get(String platform) { + return null; + } + + @Override + public boolean hasPlatform(TargetPlatform platform) { + return false; + } +} diff --git a/app/src/processing/app/helpers/ConsoleLogger.java b/app/src/processing/app/helpers/ConsoleLogger.java new file mode 100644 index 000000000..5aacc5af5 --- /dev/null +++ b/app/src/processing/app/helpers/ConsoleLogger.java @@ -0,0 +1,60 @@ +/* + * This file is part of Arduino. + * + * Copyright 2015 Ricardo JL Rufino (ricardo@criativasoft.com.br) + * Copyright 2015 Arduino LLC + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ + +package processing.app.helpers; + +import java.io.FileDescriptor; +import java.io.FileOutputStream; +import java.io.PrintStream; +import java.util.logging.LogRecord; +import java.util.logging.StreamHandler; + +public class ConsoleLogger extends StreamHandler { + + public ConsoleLogger() { + setOutputStream(new PrintStream(new FileOutputStream(FileDescriptor.out))); + } + + + public void publish(LogRecord record) { + super.publish(record); + flush(); + } + + /** + * Override StreamHandler.close to do a flush but not + * to close the output stream. That is, we do not + * close FileDescriptor.out. + */ + public void close() { + flush(); + } + +} diff --git a/app/src/processing/app/helpers/LogFormatter.java b/app/src/processing/app/helpers/LogFormatter.java new file mode 100644 index 000000000..92a0859a7 --- /dev/null +++ b/app/src/processing/app/helpers/LogFormatter.java @@ -0,0 +1,79 @@ +/* + * This file is part of Arduino. + * + * Copyright 2015 Ricardo JL Rufino (ricardo@criativasoft.com.br) + * Copyright 2015 Arduino LLC + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ + +package processing.app.helpers; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.Date; +import java.util.logging.Formatter; +import java.util.logging.LogRecord; + +public class LogFormatter extends Formatter { + + public String format; + private final Date dat = new Date(); + + public LogFormatter(String logformat) { + format = logformat; + } + + @Override + public String format(LogRecord record) { + dat.setTime(record.getMillis()); + String source; + if (record.getSourceClassName() != null) { + source = record.getSourceClassName().substring(record.getSourceClassName().lastIndexOf('.') + 1); + if (record.getSourceMethodName() != null) { + source += "." + record.getSourceMethodName(); + } + } else { + source = record.getLoggerName(); + } + String message = formatMessage(record); + String throwable = ""; + if (record.getThrown() != null) { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + pw.println(); + record.getThrown().printStackTrace(pw); + pw.close(); + throwable = sw.toString(); + } + return String.format(format, + dat, + source, + record.getLoggerName(), + record.getLevel(), + message, + throwable); + } + +} diff --git a/app/src/processing/app/macosx/ThinkDifferent.java b/app/src/processing/app/macosx/ThinkDifferent.java index e14770a9b..1f243a8d4 100644 --- a/app/src/processing/app/macosx/ThinkDifferent.java +++ b/app/src/processing/app/macosx/ThinkDifferent.java @@ -22,113 +22,95 @@ package processing.app.macosx; -import processing.app.Base; - import com.apple.eawt.*; +import processing.app.Base; +import processing.app.Editor; import java.io.File; +import java.util.List; /** * 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, + *

+ * 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 { +public class ThinkDifferent { - // 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; + private static final int MAX_WAIT_FOR_BASE = 10000; - // reference to the app where the existing quit, about, prefs code is - private Base base; + static public void init() { + Application application = Application.getApplication(); + application.setAboutHandler(new AboutHandler() { + @Override + public void handleAbout(AppEvent.AboutEvent aboutEvent) { + if (waitForBase()) { + Base.INSTANCE.handleAbout(); + } + } + }); + application.setPreferencesHandler(new PreferencesHandler() { + @Override + public void handlePreferences(AppEvent.PreferencesEvent preferencesEvent) { + if (waitForBase()) { + Base.INSTANCE.handlePrefs(); + } + } + }); + application.setOpenFileHandler(new OpenFilesHandler() { + @Override + public void openFiles(final AppEvent.OpenFilesEvent openFilesEvent) { + if (waitForBase()) { + for (File file : openFilesEvent.getFiles()) { + try { + Base.INSTANCE.handleOpen(file); + List editors = Base.INSTANCE.getEditors(); + if (editors.size() == 2 && editors.get(0).getSketch().isUntitled()) { + Base.INSTANCE.handleClose(editors.get(0)); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + } + } + }); + application.setQuitHandler(new QuitHandler() { + @Override + public void handleQuitRequestWith(AppEvent.QuitEvent quitEvent, QuitResponse quitResponse) { + if (waitForBase()) { + if (Base.INSTANCE.handleClose(Base.INSTANCE.getActiveEditor())) { + quitResponse.performQuit(); + } else { + quitResponse.cancelQuit(); + } + } + } + }); + } - - static public void init(Base base) { - if (application == null) { - //application = new com.apple.eawt.Application(); - application = com.apple.eawt.Application.getApplication(); - } - 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"); + private static boolean waitForBase() { + int slept = 0; + while (Base.INSTANCE == null) { + if (slept >= MAX_WAIT_FOR_BASE) { + return false; + } + sleep(100); + slept += 100; } + return true; } - - public void handleOpenApplication(ApplicationEvent ae) { - } - - - public void handleOpenFile(ApplicationEvent ae) { -// System.out.println("got open file event " + ae.getFilename()); - String filename = ae.getFilename(); + private static void sleep(int millis) { try { - base.handleOpen(new File(filename)); - } catch (Exception e) { - e.printStackTrace(); - } - 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"); + Thread.sleep(100); + } catch (InterruptedException e) { + //ignore } } - - - public void handleReOpenApplication(ApplicationEvent arg0) { - } + } \ No newline at end of file diff --git a/app/src/processing/app/syntax/ArduinoTokenMakerFactory.java b/app/src/processing/app/syntax/ArduinoTokenMakerFactory.java new file mode 100644 index 000000000..f1c374d80 --- /dev/null +++ b/app/src/processing/app/syntax/ArduinoTokenMakerFactory.java @@ -0,0 +1,54 @@ +/* + * This file is part of Arduino. + * + * Copyright 2015 Arduino LLC + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ + +package processing.app.syntax; + +import org.fife.ui.rsyntaxtextarea.AbstractTokenMakerFactory; +import org.fife.ui.rsyntaxtextarea.RSyntaxDocument; +import org.fife.ui.rsyntaxtextarea.TokenMaker; + +public class ArduinoTokenMakerFactory extends AbstractTokenMakerFactory { + + private final PdeKeywords pdeKeywords; + + public ArduinoTokenMakerFactory(PdeKeywords pdeKeywords) { + this.pdeKeywords = pdeKeywords; + } + + @Override + protected TokenMaker getTokenMakerImpl(String key) { + return new SketchTokenMaker(pdeKeywords); + } + + @Override + protected void initTokenMakerMap() { + putMapping(RSyntaxDocument.SYNTAX_STYLE_CPLUSPLUS, SketchTokenMaker.class.getName()); + } + +} diff --git a/app/src/processing/app/syntax/CTokenMarker.java b/app/src/processing/app/syntax/CTokenMarker.java deleted file mode 100644 index ccb9b0b48..000000000 --- a/app/src/processing/app/syntax/CTokenMarker.java +++ /dev/null @@ -1,273 +0,0 @@ -/* - * 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 - */ -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 deleted file mode 100644 index e9e23fea1..000000000 --- a/app/src/processing/app/syntax/DefaultInputHandler.java +++ /dev/null @@ -1,373 +0,0 @@ -/* - * 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 - */ -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 deleted file mode 100644 index e14671348..000000000 --- a/app/src/processing/app/syntax/InputHandler.java +++ /dev/null @@ -1,1135 +0,0 @@ -/* - * 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 - */ -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(); - public static final ActionListener CLIPBOARD_CUT = new clipboard_cut(); // [fry] - public static final ActionListener CLIPBOARD_COPY = new clipboard_copy(); - public static final ActionListener CLIPBOARD_PASTE = new clipboard_paste(); - - // 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); - actions.put("clipboard-cut",CLIPBOARD_CUT); - actions.put("clipboard-copy",CLIPBOARD_COPY); - actions.put("clipboard-paste",CLIPBOARD_PASTE); - } - - /** - * 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 clipboard_cut implements ActionListener - { - public void actionPerformed(ActionEvent evt) - { - getTextArea(evt).cut(); - } - } - - - public static class clipboard_copy implements ActionListener - { - public void actionPerformed(ActionEvent evt) - { - getTextArea(evt).copy(); - } - } - - - public static class clipboard_paste implements ActionListener - { - public void actionPerformed(ActionEvent evt) - { - getTextArea(evt).paste(); - } - } - - - 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 deleted file mode 100644 index c12102038..000000000 --- a/app/src/processing/app/syntax/JEditTextArea.java +++ /dev/null @@ -1,2448 +0,0 @@ -/* -*- 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; -import java.awt.im.InputMethodRequests; - -import processing.app.syntax.im.InputMethodSupport; - -/** - * 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 - */ -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); - editorLineNumbers = new TextAreaLineNumbers(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(LEFT, editorLineNumbers); - 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()); - // send tab keys through to the text area - // http://dev.processing.org/bugs/show_bug.cgi?id=1267 - setFocusTraversalKeysEnabled(false); - - // 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); - } - }); - } - - /** - * Inline Input Method Support for Japanese. - */ - private InputMethodSupport inputMethodSupport = null; - public InputMethodRequests getInputMethodRequests() { - if (inputMethodSupport == null) { - inputMethodSupport = new InputMethodSupport(this); - } - return inputMethodSupport; - } - - /** - * 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); - } - updateLineNumbers(); - } - - private void updateLineNumbers() { - if (editorLineNumbers != null) { - editorLineNumbers.updateLineNumbers(getFirstLine() + 1, Math.min(getFirstLine() + getVisibleLines() + 1, getLineCount())); - editorLineNumbers.updateWidthForNumDigits(String.valueOf(getLineCount()).length()); - } - } - - /** - * 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(); - } - repaintEditor(); - } - - /** - * 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(); - repaintEditor(); - } - - /** - * 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(); - repaintEditor(); - } - - return changed; - } - - private void repaintEditor() { - painter.repaint(); - updateLineNumbers(); - } - - /** - * 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(); - repaintEditor(); - } - - - /** - * 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); - repaintEditor(); - } - - - /** - * 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() - { - if (document != null) { - return document.getDefaultRootElement().getElementCount(); - } else { - return 0; - } - } - - /** - * 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 end offset of the specified line, but not past the end of the text - * @param line The line - * @return The end offset of the specified line, safe to use for a selection, or -1 if the line is - * invalid. - */ - public int getSafeLineStopOffset(int line) - { - return Math.min(getLineStopOffset(line),getDocumentLength()); - } - - /** - * 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 (newEnd > getDocumentLength()) { - newEnd = getDocumentLength(); - } - - if(newStart < 0) - { - throw new IllegalArgumentException("Bounds out of" - + " range: " + newStart + "," + - newEnd + " [" + getDocumentLength() + "]"); - } - - // 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; - - if (newStart != newEnd) { - Clipboard unixclipboard = getToolkit().getSystemSelection(); - if (unixclipboard != null) { - String selection = getSelectedText(); - if (selection != null) { - unixclipboard.setContents(new StringSelection(selection), null); - } - } - } - - 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)); - } - } - - private boolean isWordCharacter( char ch, String noWordSep ) - { - return Character.isLetterOrDigit(ch) || ch=='_' || noWordSep.indexOf(ch) != -1; - } - - protected void setNewSelectionWord( int line, int offset ) - { - if (getLineLength(line) == 0) { - newSelectionStart = getLineStartOffset(line); - newSelectionEnd = newSelectionStart; - return; - } - - String noWordSep = (String)document.getProperty("noWordSep"); - if(noWordSep == null) - noWordSep = ""; - - 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 = !isWordCharacter(ch,noWordSep); - - for(int i = offset - 1; i >= 0; i--) { - ch = lineText.charAt(i); - if (selectNoLetter ^ !isWordCharacter(ch,noWordSep)) { - wordStart = i + 1; - break; - } - } - - for(int i = offset; i < lineText.length(); i++) { - ch = lineText.charAt(i); - if(selectNoLetter ^ !isWordCharacter(ch,noWordSep)) { - wordEnd = i; - break; - } - } - //} - int lineStart = getLineStartOffset(line); - - newSelectionStart = lineStart + wordStart; - newSelectionEnd = lineStart + wordEnd; - } - - - /** - * 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); - - Transferable t = new StringSelection(buf.toString()); - clipboard.setContents(t, null); - - Clipboard unixclipboard = getToolkit().getSystemSelection(); - if (unixclipboard != null) unixclipboard.setContents(t, 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 LEFT = "left"; - 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 TextAreaLineNumbers editorLineNumbers; - - //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 newSelectionStart; // hack to get around lack of multiple returns in Java - protected int newSelectionEnd; - - protected boolean selectWord; - protected boolean selectLine; - protected int selectionAncorStart; - protected int selectionAncorEnd; - - 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(LEFT)) - left = comp; - else 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(left == comp) - left = null; - 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 leftPref = left.getPreferredSize(); - dim.width += leftPref.width; - 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 leftPref = left.getMinimumSize(); - dim.width += leftPref.width; - 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 leftWidth = left.getSize().width; - int rightWidth = right.getPreferredSize().width; - int bottomHeight = bottom.getPreferredSize().height; - int centerWidth = size.width - leftWidth - rightWidth - ileft - iright; - int centerHeight = size.height - bottomHeight - itop - ibottom; - - left.setBounds(ileft, - itop, - leftWidth, - centerHeight); - - ileft += leftWidth; - - 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 left; - private Component center; - private Component right; - private Component bottom; - private Vector leftOfScrollBar = new Vector(); - } - - static class CaretBlinker implements ActionListener - { - public void actionPerformed(ActionEvent evt) - { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - 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; - - if ( !selectWord && !selectLine ) { - setSelectionRectangular((evt.getModifiers() - & InputEvent.CTRL_MASK) != 0); - select(getMarkPosition(),xyToOffset(evt.getX(),evt.getY())); - } else { - int line = yToLine(evt.getY()); - if ( selectWord ) { - setNewSelectionWord( line, xToOffset(line,evt.getX()) ); - } else { - newSelectionStart = getLineStartOffset(line); - newSelectionEnd = getSafeLineStopOffset(line); - } - if ( newSelectionStart < selectionAncorStart ) { - select(newSelectionStart,selectionAncorEnd); - } else if ( newSelectionEnd > selectionAncorEnd ) { - select(selectionAncorStart,newSelectionEnd); - } else { - select(newSelectionStart,newSelectionEnd); - } - } - } - - final Cursor normalCursor = new Cursor(Cursor.DEFAULT_CURSOR); - final Cursor handCursor = new Cursor(Cursor.HAND_CURSOR); - - public void mouseMoved(MouseEvent evt) { - int line = yToLine(evt.getY()); - int offset = xToOffset(line, evt.getX()); - boolean wantHandCursor = checkClickedURL(getLineText(line), offset) != null; - JComponent src = (JComponent) evt.getSource(); - if (wantHandCursor) - src.setCursor(handCursor); - else - src.setCursor(normalCursor); - } - } - - 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; - } - } - - public String checkClickedURL(String line, int offset) { - String[] parse = SyntaxUtilities.parseCommentUrls(line); - if (parse==null) - return null; - int start = parse[0].length(); - int stop = start + parse[1].length(); - if (offsetstop) - return null; - return parse[1]; - } - - 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; - } - - // on Linux, middle button pastes selected text - if ((evt.getModifiers() & InputEvent.BUTTON2_MASK) != 0) { - Clipboard unixclipboard = getToolkit().getSystemSelection(); - if (unixclipboard != null) { - Transferable t = unixclipboard.getContents(null); - if (t != null && t.isDataFlavorSupported(DataFlavor.stringFlavor)) { - try { - String s = (String)t.getTransferData(DataFlavor.stringFlavor); - s = s.replace('\u00A0', ' '); - if (editable) setSelectedText(s); - } catch (Exception e) { - System.err.println(e); - e.printStackTrace(); - } - } - return; - } - } - - int line = yToLine(evt.getY()); - int offset = xToOffset(line,evt.getX()); - int dot = getLineStartOffset(line) + offset; - - selectLine = false; - selectWord = false; - - 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) { - // Check for click on urls - String clickedURL = checkClickedURL(getLineText(line), offset); - if (clickedURL != null) { - Base.openURL(clickedURL); - return; - } - - 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(); - } - - setNewSelectionWord( line, offset ); - select(newSelectionStart,newSelectionEnd); - selectWord = true; - selectionAncorStart = selectionStart; - selectionAncorEnd = selectionEnd; - - /* - 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) - { - selectLine = true; - select(getLineStartOffset(line),getSafeLineStopOffset(line)); - selectionAncorStart = selectionStart; - selectionAncorEnd = selectionEnd; - } - } - - 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(); - } - - public void setDisplayLineNumbers(boolean displayLineNumbers) { - editorLineNumbers.setDisplayLineNumbers(displayLineNumbers); - } -} diff --git a/app/src/processing/app/syntax/KeywordMap.java b/app/src/processing/app/syntax/KeywordMap.java deleted file mode 100644 index 27d225f8c..000000000 --- a/app/src/processing/app/syntax/KeywordMap.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * 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 - */ -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 index ccf52531c..3b5a575ce 100644 --- a/app/src/processing/app/syntax/PdeKeywords.java +++ b/app/src/processing/app/syntax/PdeKeywords.java @@ -24,106 +24,158 @@ package processing.app.syntax; -import processing.app.*; +import cc.arduino.contributions.libraries.ContributedLibrary; +import org.fife.ui.rsyntaxtextarea.TokenMap; +import org.fife.ui.rsyntaxtextarea.TokenTypes; +import processing.app.Base; +import processing.app.BaseNoGui; import processing.app.legacy.PApplet; -import processing.app.packages.Library; -import java.io.*; -import java.util.*; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStreamReader; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Pattern; -public class PdeKeywords extends CTokenMarker { +public class PdeKeywords { - // lookup table for the TokenMarker subclass, handles coloring - static KeywordMap keywordColoring; + private static final Map KNOWN_TOKEN_TYPES = new HashMap(); + private static final Pattern ALPHA = Pattern.compile("\\w"); - // lookup table that maps keywords to their html reference pages - static Hashtable keywordToReference; - - - public PdeKeywords() { - super(false, getKeywords()); + static { + KNOWN_TOKEN_TYPES.put("RESERVED_WORD", TokenTypes.RESERVED_WORD); + KNOWN_TOKEN_TYPES.put("RESERVED_WORD_2", TokenTypes.RESERVED_WORD_2); + KNOWN_TOKEN_TYPES.put("VARIABLE", TokenTypes.VARIABLE); + KNOWN_TOKEN_TYPES.put("OPERATOR", TokenTypes.OPERATOR); + KNOWN_TOKEN_TYPES.put("DATA_TYPE", TokenTypes.DATA_TYPE); + KNOWN_TOKEN_TYPES.put("LITERAL_BOOLEAN", TokenTypes.LITERAL_BOOLEAN); + KNOWN_TOKEN_TYPES.put("LITERAL_CHAR", TokenTypes.LITERAL_CHAR); } + // lookup table for the TokenMarker subclass, handles coloring + private final TokenMap keywordTokenType; + private final Map keywordOldToken; + private final Map keywordTokenTypeAsString; + + // lookup table that maps keywords to their html reference pages + private final Map keywordToReference; + + public PdeKeywords() { + this.keywordTokenType = new TokenMap(); + this.keywordOldToken = new HashMap(); + this.keywordTokenTypeAsString = new HashMap(); + this.keywordToReference = new HashMap(); + } /** * 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(); - getKeywords(Base.getLibStream("keywords.txt")); - for (Library lib : Base.getLibraries()) { - File keywords = new File(lib.getFolder(), "keywords.txt"); - if (keywords.exists()) getKeywords(new FileInputStream(keywords)); + public void reload() { + try { + parseKeywordsTxt(new File(BaseNoGui.getContentFile("lib"), "keywords.txt")); + for (ContributedLibrary lib : Base.getLibraries()) { + File keywords = new File(lib.getInstalledFolder(), "keywords.txt"); + if (keywords.exists()) { + parseKeywordsTxt(keywords); } - } catch (Exception e) { - Base.showError("Problem loading keywords", - "Could not load keywords.txt,\n" + - "please re-install Arduino.", e); - System.exit(1); } + } catch (Exception e) { + Base.showError("Problem loading keywords", "Could not load keywords.txt,\nplease re-install Arduino.", e); + System.exit(1); } - return keywordColoring; } - - static private void getKeywords(InputStream input) throws Exception { - 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; + private void parseKeywordsTxt(File input) throws Exception { + BufferedReader reader = null; + try { + reader = new BufferedReader(new InputStreamReader(new FileInputStream(input))); - String pieces[] = 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 line; + while ((line = reader.readLine()) != null) { + //System.out.println("line is " + line); + // in case there's any garbage on the line + line = line.trim(); + if (line.length() == 0 || line.startsWith("#")) { + continue; + } + + String pieces[] = PApplet.split(line, '\t'); 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 && Character.isDigit(coloring.charAt(coloring.length() - 1))) { - // 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 >= 2) { + keywordOldToken.put(keyword, pieces[1]); } + if (pieces.length >= 3) { - String htmlFilename = pieces[2].trim(); - if (htmlFilename.length() > 0) { - keywordToReference.put(keyword, htmlFilename); - } + parseHTMLReferenceFileName(pieces[2], keyword); + } + if (pieces.length >= 4) { + parseRSyntaxTextAreaTokenType(pieces[3], keyword); + } + } + + fillMissingTokenType(); + } finally { + if (reader != null) { + reader.close(); + } + } + + } + + private void fillMissingTokenType() { + for (Map.Entry oldTokenEntry : keywordOldToken.entrySet()) { + String keyword = oldTokenEntry.getKey(); + if (!keywordTokenTypeAsString.containsKey(keyword)) { + if ("KEYWORD1".equals(oldTokenEntry.getValue())) { + parseRSyntaxTextAreaTokenType("DATA_TYPE", keyword); + } else { + parseRSyntaxTextAreaTokenType("FUNCTION", keyword); } } } - reader.close(); } + private void parseRSyntaxTextAreaTokenType(String tokenTypeAsString, String keyword) { + if (!ALPHA.matcher(keyword).find()) { + return; + } - static public String getReference(String keyword) { - return (String) keywordToReference.get(keyword); + if (KNOWN_TOKEN_TYPES.containsKey(tokenTypeAsString)) { + keywordTokenType.put(keyword, KNOWN_TOKEN_TYPES.get(tokenTypeAsString)); + keywordTokenTypeAsString.put(keyword, tokenTypeAsString); + } else { + keywordTokenType.put(keyword, TokenTypes.FUNCTION); + keywordTokenTypeAsString.put(keyword, "FUNCTION"); + } + } + + private void parseHTMLReferenceFileName(String piece, String keyword) { + String htmlFilename = piece.trim(); + if (htmlFilename.length() > 0) { + keywordToReference.put(keyword, htmlFilename); + } + } + + public String getReference(String keyword) { + return keywordToReference.get(keyword); + } + + public String getTokenTypeAsString(String keyword) { + return keywordTokenTypeAsString.get(keyword); + } + + public int getTokenType(char[] array, int start, int end) { + return keywordTokenType.get(array, start, end); } } diff --git a/app/src/processing/app/syntax/PdeTextAreaDefaults.java b/app/src/processing/app/syntax/PdeTextAreaDefaults.java deleted file mode 100644 index 2ff65afa8..000000000 --- a/app/src/processing/app/syntax/PdeTextAreaDefaults.java +++ /dev/null @@ -1,211 +0,0 @@ -/* -*- 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.*; -import processing.app.helpers.OSUtils; - - -public class PdeTextAreaDefaults extends TextAreaDefaults { - - public PdeTextAreaDefaults() { - - inputHandler = new DefaultInputHandler(); - //inputHandler.addDefaultKeyBindings(); // 0122 - - // use option on mac for text edit controls that are ctrl on windows/linux - String mod = OSUtils.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); - // for 0122, shift-backspace is delete, for 0176, it's now a preference, - // to prevent holy warriors from attacking me for it. - if (Preferences.getBoolean("editor.keys.shift_backspace_is_delete")) { - inputHandler.addKeyBinding("S+BACK_SPACE", InputHandler.DELETE); - } else { - inputHandler.addKeyBinding("S+BACK_SPACE", InputHandler.BACKSPACE); - } - - inputHandler.addKeyBinding("DELETE", 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); - - // http://dev.processing.org/bugs/show_bug.cgi?id=162 - // added for 0176, though the bindings do not appear relevant for osx - if (Preferences.getBoolean("editor.keys.alternative_cut_copy_paste")) { - inputHandler.addKeyBinding("C+INSERT", InputHandler.CLIPBOARD_COPY); - inputHandler.addKeyBinding("S+INSERT", InputHandler.CLIPBOARD_PASTE); - inputHandler.addKeyBinding("S+DELETE", InputHandler.CLIPBOARD_CUT); - } - - // disabling for 0122, not sure what this does - //inputHandler.addKeyBinding("C+\\", InputHandler.TOGGLE_RECT); - - // for 0122, these have been changed for better compatibility - // HOME and END now mean the beginning/end of the document - // for 0176 changed this to a preference so that the Mac OS X people - // can get the "normal" behavior as well if they prefer. - if (Preferences.getBoolean("editor.keys.home_and_end_travel_far")) { - 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 (OSUtils.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"); - - // http://arduino.cc/ - styles[Token.URL] = Theme.getStyle("url"); - - // + - = / - 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/SketchTextArea.java b/app/src/processing/app/syntax/SketchTextArea.java new file mode 100644 index 000000000..580fe99f7 --- /dev/null +++ b/app/src/processing/app/syntax/SketchTextArea.java @@ -0,0 +1,474 @@ +/* + * This file is part of Arduino. + * + * Copyright 2015 Ricardo JL Rufino (ricardo@criativasoft.com.br) + * Copyright 2015 Arduino LLC + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ + +package processing.app.syntax; + +import org.fife.ui.rsyntaxtextarea.*; +import org.fife.ui.rsyntaxtextarea.Theme; +import org.fife.ui.rsyntaxtextarea.Token; +import org.fife.ui.rsyntaxtextarea.focusabletip.FocusableTip; +import org.fife.ui.rtextarea.RTextArea; +import org.fife.ui.rtextarea.RTextAreaUI; +import org.fife.ui.rtextarea.RUndoManager; +import processing.app.*; + +import javax.swing.*; +import javax.swing.event.EventListenerList; +import javax.swing.event.HyperlinkEvent; +import javax.swing.event.HyperlinkListener; +import javax.swing.text.BadLocationException; +import javax.swing.text.Document; +import javax.swing.text.Segment; +import javax.swing.undo.UndoManager; +import java.awt.*; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.logging.Logger; + +/** + * Arduino Sketch code editor based on RSyntaxTextArea (http://fifesoft.com/rsyntaxtextarea) + * + * @author Ricardo JL Rufino (ricardo@criativasoft.com.br) + * @date 20/04/2015 + * @since 1.6.4 + */ +public class SketchTextArea extends RSyntaxTextArea { + + private final static Logger LOG = Logger.getLogger(SketchTextArea.class.getName()); + + /** + * The last docTooltip displayed. + */ + private FocusableTip docTooltip; + + private EditorListener editorListener; + + private final PdeKeywords pdeKeywords; + + public SketchTextArea(PdeKeywords pdeKeywords) throws IOException { + this.pdeKeywords = pdeKeywords; + installFeatures(); + } + + protected void installFeatures() throws IOException { + setTheme(PreferencesData.get("editor.syntax_theme", "default")); + + setLinkGenerator(new DocLinkGenerator(pdeKeywords)); + + fixControlTab(); + + setSyntaxEditingStyle(SYNTAX_STYLE_CPLUSPLUS); + } + + public void setTheme(String name) throws IOException { + FileInputStream defaultXmlInputStream = null; + try { + defaultXmlInputStream = new FileInputStream(new File(BaseNoGui.getContentFile("lib"), "theme/syntax/" + name + ".xml")); + Theme theme = Theme.load(defaultXmlInputStream); + theme.apply(this); + } finally { + if (defaultXmlInputStream != null) { + defaultXmlInputStream.close(); + } + } + + setForeground(processing.app.Theme.getColor("editor.fgcolor")); + setBackground(processing.app.Theme.getColor("editor.bgcolor")); + setCurrentLineHighlightColor(processing.app.Theme.getColor("editor.linehighlight.color")); + setCaretColor(processing.app.Theme.getColor("editor.caret.color")); + setSelectedTextColor(null); + setUseSelectedTextColor(false); + setSelectionColor(processing.app.Theme.getColor("editor.selection.color")); + setMatchedBracketBorderColor(processing.app.Theme.getColor("editor.brackethighlight.color")); + setHyperlinkForeground((Color) processing.app.Theme.getStyledFont("url", getFont()).get("color")); + + setSyntaxTheme(TokenTypes.DATA_TYPE, "data_type"); + setSyntaxTheme(TokenTypes.FUNCTION, "function"); + setSyntaxTheme(TokenTypes.RESERVED_WORD, "reserved_word"); + setSyntaxTheme(TokenTypes.RESERVED_WORD_2, "reserved_word_2"); + setSyntaxTheme(TokenTypes.VARIABLE, "variable"); + setSyntaxTheme(TokenTypes.OPERATOR, "operator"); + setSyntaxTheme(TokenTypes.COMMENT_DOCUMENTATION, "comment1"); + setSyntaxTheme(TokenTypes.COMMENT_EOL, "comment1"); + setSyntaxTheme(TokenTypes.COMMENT_KEYWORD, "comment1"); + setSyntaxTheme(TokenTypes.COMMENT_MARKUP, "comment1"); + setSyntaxTheme(TokenTypes.LITERAL_CHAR, "literal_char"); + setSyntaxTheme(TokenTypes.LITERAL_STRING_DOUBLE_QUOTE, "literal_string_double_quote"); + } + + private void setSyntaxTheme(int tokenType, String id) { + Style style = getSyntaxScheme().getStyle(tokenType); + + Map styledFont = processing.app.Theme.getStyledFont(id, style.font); + style.foreground = (Color) styledFont.get("color"); + style.font = (Font) styledFont.get("font"); + + getSyntaxScheme().setStyle(tokenType, style); + } + + // Removing the default focus traversal keys + // This is because the DefaultKeyboardFocusManager handles the keypress and consumes the event + protected void fixControlTab() { + removeCTRLTabFromFocusTraversal(); + + removeCTRLSHIFTTabFromFocusTraversal(); + } + + private void removeCTRLSHIFTTabFromFocusTraversal() { + KeyStroke ctrlShiftTab = KeyStroke.getKeyStroke("ctrl shift TAB"); + Set backwardKeys = new HashSet(this.getFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS)); + backwardKeys.remove(ctrlShiftTab); + } + + private void removeCTRLTabFromFocusTraversal() { + KeyStroke ctrlTab = KeyStroke.getKeyStroke("ctrl TAB"); + Set forwardKeys = new HashSet(this.getFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS)); + forwardKeys.remove(ctrlTab); + this.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, forwardKeys); + } + + + @Override + public void select(int selectionStart, int selectionEnd) { + super.select(selectionStart, selectionEnd); + } + + public boolean isSelectionActive() { + return this.getSelectedText() != null; + } + + public void setSelectedText(String text) { + + int old = getTextMode(); + setTextMode(OVERWRITE_MODE); + replaceSelection(text); + setTextMode(old); + + } + + public void processKeyEvent(KeyEvent evt) { + + // this had to be added because the menu key events weren't making it up to the frame. + + switch (evt.getID()) { + case KeyEvent.KEY_TYPED: + if (editorListener != null) editorListener.keyTyped(evt); + break; + case KeyEvent.KEY_PRESSED: + if (editorListener != null) editorListener.keyPressed(evt); + break; + case KeyEvent.KEY_RELEASED: + // inputHandler.keyReleased(evt); + break; + } + + if (!evt.isConsumed()) { + super.processKeyEvent(evt); + } + } + + public void switchDocument(Document document, UndoManager newUndo) { + + // HACK: Dont discard changes on curret UndoManager. + // BUG: https://github.com/bobbylight/RSyntaxTextArea/issues/84 + setUndoManager(null); // bypass reset current undo manager... + + super.setDocument(document); + + setUndoManager((RUndoManager) newUndo); + + // HACK: Complement previous hack (hide code folding on switch) | Drawback: Lose folding state +// if(sketch.getCodeCount() > 1 && textarea.isCodeFoldingEnabled()){ +// textarea.setCodeFoldingEnabled(false); +// textarea.setCodeFoldingEnabled(true); +// } + + + } + + @Override + protected JPopupMenu createPopupMenu() { + JPopupMenu menu = super.createPopupMenu(); + return menu; + } + + @Override + protected void configurePopupMenu(JPopupMenu popupMenu) { + super.configurePopupMenu(popupMenu); + } + + @Override + protected RTAMouseListener createMouseListener() { + return new SketchTextAreaMouseListener(this); + } + + public void getTextLine(int line, Segment segment) { + try { + int offset = getLineStartOffset(line); + int end = getLineEndOffset(line); + getDocument().getText(offset, end - offset, segment); + } catch (BadLocationException e) { + } + } + + public String getTextLine(int line) { + try { + int offset = getLineStartOffset(line); + int end = getLineEndOffset(line); + return getDocument().getText(offset, end - offset); + } catch (BadLocationException e) { + return null; + } + } + + + public void setEditorListener(EditorListener editorListener) { + this.editorListener = editorListener; + } + + private static class DocLinkGenerator implements LinkGenerator { + + private final PdeKeywords pdeKeywords; + + public DocLinkGenerator(PdeKeywords pdeKeywords) { + this.pdeKeywords = pdeKeywords; + } + + @Override + public LinkGeneratorResult isLinkAtOffset(RSyntaxTextArea textArea, final int offs) { + + final Token token = textArea.modelToToken(offs); + + final String reference = pdeKeywords.getReference(token.getLexeme()); + + // LOG.fine("reference: " + reference + ", match: " + (token.getType() == TokenTypes.DATA_TYPE || token.getType() == TokenTypes.VARIABLE || token.getType() == TokenTypes.FUNCTION)); + + if (token != null && (reference != null || (token.getType() == TokenTypes.DATA_TYPE || token.getType() == TokenTypes.VARIABLE || token.getType() == TokenTypes.FUNCTION))) { + + LinkGeneratorResult generatorResult = new LinkGeneratorResult() { + + @Override + public int getSourceOffset() { + return offs; + } + + @Override + public HyperlinkEvent execute() { + + LOG.fine("Open Reference: " + reference); + + Base.showReference("Reference/" + reference); + + return null; + } + }; + + return generatorResult; + } + + return null; + } + } + + + /** + * Handles http hyperlinks. + * NOTE (@Ricardo JL Rufino): Workaround to enable hyperlinks by default: https://github.com/bobbylight/RSyntaxTextArea/issues/119 + */ + private class SketchTextAreaMouseListener extends RTextAreaMutableCaretEvent { + + private Insets insets; + private boolean isScanningForLinks; + private int hoveredOverLinkOffset = -1; + + protected SketchTextAreaMouseListener(RTextArea textArea) { + super(textArea); + insets = new Insets(0, 0, 0, 0); + } + + /** + * Notifies all listeners that have registered interest for notification + * on this event type. The listener list is processed last to first. + * + * @param e The event to fire. + * @see EventListenerList + */ + private void fireHyperlinkUpdate(HyperlinkEvent e) { + // Guaranteed to return a non-null array + Object[] listeners = listenerList.getListenerList(); + // Process the listeners last to first, notifying + // those that are interested in this event + for (int i = listeners.length - 2; i >= 0; i -= 2) { + if (listeners[i] == HyperlinkListener.class) { + ((HyperlinkListener) listeners[i + 1]).hyperlinkUpdate(e); + } + } + } + + private HyperlinkEvent createHyperlinkEvent(MouseEvent e) { + HyperlinkEvent he = null; + + Token t = viewToToken(e.getPoint()); + if (t != null) { + // Copy token, viewToModel() unfortunately modifies Token + t = new TokenImpl(t); + } + + if (t != null && t.isHyperlink()) { + URL url = null; + String desc = null; + try { + String temp = t.getLexeme(); + // URI's need "http://" prefix for web URL's to work. + if (temp.startsWith("www.")) { + temp = "http://" + temp; + } + url = new URL(temp); + } catch (MalformedURLException mue) { + desc = mue.getMessage(); + } + he = new HyperlinkEvent(SketchTextArea.this, HyperlinkEvent.EventType.ACTIVATED, url, desc); + } + + return he; + } + + @Override + public void mouseClicked(MouseEvent e) { + if (getHyperlinksEnabled()) { + HyperlinkEvent he = createHyperlinkEvent(e); + if (he != null) { + fireHyperlinkUpdate(he); + } + } + } + + @Override + public void mouseMoved(MouseEvent e) { + + super.mouseMoved(e); + + if (!getHyperlinksEnabled()) { + return; + } + +// LinkGenerator linkGenerator = getLinkGenerator(); + + // GitHub issue RSyntaxTextArea/#25 - links identified at "edges" of editor + // should not be activated if mouse is in margin insets. + insets = getInsets(insets); + if (insets != null) { + int x = e.getX(); + int y = e.getY(); + if (x <= insets.left || y < insets.top) { + if (isScanningForLinks) { + stopScanningForLinks(); + } + return; + } + } + + isScanningForLinks = true; + Token t = viewToToken(e.getPoint()); + if (t != null) { + // Copy token, viewToModel() unfortunately modifies Token + t = new TokenImpl(t); + } + Cursor c2 = null; + if (t != null && t.isHyperlink()) { + if (hoveredOverLinkOffset == -1 || + hoveredOverLinkOffset != t.getOffset()) { + hoveredOverLinkOffset = t.getOffset(); + repaint(); + } + c2 = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR); + } +// else if (t!=null && linkGenerator!=null) { +// int offs = viewToModel(e.getPoint()); +// LinkGeneratorResult newResult = linkGenerator. +// isLinkAtOffset(SketchTextArea.this, offs); +// if (newResult!=null) { +// // Repaint if we're at a new link now. +// if (linkGeneratorResult==null || +// !equal(newResult, linkGeneratorResult)) { +// repaint(); +// } +// linkGeneratorResult = newResult; +// hoveredOverLinkOffset = t.getOffset(); +// c2 = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR); +// } +// else { +// // Repaint if we've moved off of a link. +// if (linkGeneratorResult!=null) { +// repaint(); +// } +// c2 = Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR); +// hoveredOverLinkOffset = -1; +// linkGeneratorResult = null; +// } +// } + else { + c2 = Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR); + hoveredOverLinkOffset = -1; + // linkGeneratorResult = null; + } + if (getCursor() != c2) { + setCursor(c2); + // TODO: Repaint just the affected line(s). + repaint(); // Link either left or went into. + } + } + + private void stopScanningForLinks() { + if (isScanningForLinks) { + Cursor c = getCursor(); + isScanningForLinks = false; + if (c != null && c.getType() == Cursor.HAND_CURSOR) { + setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR)); + repaint(); // TODO: Repaint just the affected line. + } + } + } + + } + + @Override + protected RTextAreaUI createRTextAreaUI() { + return new SketchTextAreaUI(this); + } +} diff --git a/app/src/processing/app/syntax/SketchTextAreaDefaultInputMap.java b/app/src/processing/app/syntax/SketchTextAreaDefaultInputMap.java new file mode 100644 index 000000000..5d806f4c9 --- /dev/null +++ b/app/src/processing/app/syntax/SketchTextAreaDefaultInputMap.java @@ -0,0 +1,43 @@ +package processing.app.syntax; + +import org.fife.ui.rsyntaxtextarea.RSyntaxTextAreaDefaultInputMap; +import org.fife.ui.rtextarea.RTextArea; +import org.fife.ui.rtextarea.RTextAreaEditorKit; +import processing.app.PreferencesData; + +import javax.swing.*; +import javax.swing.text.DefaultEditorKit; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; + +public class SketchTextAreaDefaultInputMap extends RSyntaxTextAreaDefaultInputMap { + + public SketchTextAreaDefaultInputMap() { + int defaultModifier = getDefaultModifier(); + int alt = InputEvent.ALT_MASK; + boolean isOSX = RTextArea.isOSX(); + int moveByWordMod = isOSX ? alt : defaultModifier; + + remove(KeyStroke.getKeyStroke(KeyEvent.VK_K, defaultModifier)); + + if (PreferencesData.getBoolean("editor.advanced")) { + put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, alt), RTextAreaEditorKit.rtaLineDownAction); + put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, alt), RTextAreaEditorKit.rtaLineUpAction); + } else { + remove(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, alt)); + remove(KeyStroke.getKeyStroke(KeyEvent.VK_UP, alt)); + } + + remove(KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, defaultModifier)); + put(KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, moveByWordMod), RTextAreaEditorKit.rtaDeletePrevWordAction); + + if (isOSX) { + put(KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, defaultModifier), SketchTextAreaEditorKit.rtaDeleteLineToCursorAction); + + put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, defaultModifier), DefaultEditorKit.beginAction); + put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, defaultModifier), DefaultEditorKit.endAction); + + remove(KeyStroke.getKeyStroke(KeyEvent.VK_J, defaultModifier)); + } + } +} diff --git a/app/src/processing/app/syntax/SketchTextAreaEditorKit.java b/app/src/processing/app/syntax/SketchTextAreaEditorKit.java new file mode 100644 index 000000000..b31bfcb2e --- /dev/null +++ b/app/src/processing/app/syntax/SketchTextAreaEditorKit.java @@ -0,0 +1,103 @@ +package processing.app.syntax; + +import org.fife.ui.rsyntaxtextarea.RSyntaxTextAreaEditorKit; +import org.fife.ui.rtextarea.RTextArea; +import org.fife.ui.rtextarea.RecordableTextAction; + +import javax.swing.*; +import javax.swing.text.*; +import java.awt.event.ActionEvent; + +public class SketchTextAreaEditorKit extends RSyntaxTextAreaEditorKit { + + public static final String rtaDeleteNextWordAction = "RTA.DeleteNextWordAction"; + public static final String rtaDeleteLineToCursorAction = "RTA.DeleteLineToCursorAction"; + + private static final Action[] defaultActions = { + new DeleteNextWordAction(), + new DeleteLineToCursorAction() + }; + + @Override + public Action[] getActions() { + return TextAction.augmentList(super.getActions(), SketchTextAreaEditorKit.defaultActions); + } + + public static class DeleteNextWordAction extends RecordableTextAction { + + public DeleteNextWordAction() { + super(rtaDeleteNextWordAction); + } + + @Override + public void actionPerformedImpl(ActionEvent e, RTextArea textArea) { + if (!textArea.isEditable() || !textArea.isEnabled()) { + UIManager.getLookAndFeel().provideErrorFeedback(textArea); + return; + } + try { + int start = textArea.getSelectionStart(); + int end = getNextWordStart(textArea, start); + if (end > start) { + textArea.getDocument().remove(start, end - start); + } + } catch (BadLocationException ex) { + UIManager.getLookAndFeel().provideErrorFeedback(textArea); + } + } + + @Override + public String getMacroID() { + return rtaDeleteNextWordAction; + } + + /** + * Returns the starting offset to delete. Exists so subclasses can + * override. + */ + protected int getNextWordStart(RTextArea textArea, int end) + throws BadLocationException { + return Utilities.getNextWord(textArea, end); + } + + } + + public static class DeleteLineToCursorAction extends RecordableTextAction { + + public DeleteLineToCursorAction() { + super(rtaDeleteLineToCursorAction); + } + + @Override + public void actionPerformedImpl(ActionEvent e, RTextArea textArea) { + if (!textArea.isEditable() || !textArea.isEnabled()) { + UIManager.getLookAndFeel().provideErrorFeedback(textArea); + return; + } + try { + + // We use the elements instead of calling getLineOfOffset(), + // etc. to speed things up just a tad (i.e. micro-optimize). + Document document = textArea.getDocument(); + int caretPosition = textArea.getCaretPosition(); + Element map = document.getDefaultRootElement(); + int currentLineNum = map.getElementIndex(caretPosition); + Element currentLineElement = map.getElement(currentLineNum); + int currentLineStart = currentLineElement.getStartOffset(); + if (caretPosition > currentLineStart) { + document.remove(currentLineStart, caretPosition - currentLineStart); + } + + } catch (BadLocationException ble) { + ble.printStackTrace(); + } + } + + @Override + public String getMacroID() { + return rtaDeleteLineToCursorAction; + } + + } + +} diff --git a/app/src/processing/app/syntax/SketchTextAreaUI.java b/app/src/processing/app/syntax/SketchTextAreaUI.java new file mode 100644 index 000000000..7ae86a102 --- /dev/null +++ b/app/src/processing/app/syntax/SketchTextAreaUI.java @@ -0,0 +1,21 @@ +package processing.app.syntax; + +import org.fife.ui.rsyntaxtextarea.RSyntaxTextAreaUI; + +import javax.swing.*; +import javax.swing.text.EditorKit; +import javax.swing.text.JTextComponent; + +public class SketchTextAreaUI extends RSyntaxTextAreaUI { + + private static final EditorKit defaultKit = new SketchTextAreaEditorKit(); + + public SketchTextAreaUI(JComponent rSyntaxTextArea) { + super(rSyntaxTextArea); + } + + @Override + public EditorKit getEditorKit(JTextComponent tc) { + return defaultKit; + } +} diff --git a/app/src/processing/app/syntax/SketchTokenMaker.java b/app/src/processing/app/syntax/SketchTokenMaker.java new file mode 100644 index 000000000..92f105bc5 --- /dev/null +++ b/app/src/processing/app/syntax/SketchTokenMaker.java @@ -0,0 +1,62 @@ +/* + * This file is part of Arduino. + * + * Copyright 2015 Ricardo JL Rufino (ricardo@criativasoft.com.br) + * Copyright 2015 Arduino LLC + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ + +package processing.app.syntax; + +import org.fife.ui.rsyntaxtextarea.modes.CPlusPlusTokenMaker; + +import java.util.Arrays; + +/** + * Controls the syntax highlighting of {@link SketchTextArea} based on the {@link PdeKeywords} + * + * @author Ricardo JL Rufino (ricardo@criativasoft.com.br) + * @date 20/04/2015 + * @since 1.6.4 + */ +public class SketchTokenMaker extends CPlusPlusTokenMaker { + + private final PdeKeywords pdeKeywords; + + public SketchTokenMaker(PdeKeywords pdeKeywords) { + this.pdeKeywords = pdeKeywords; + } + + @Override + public void addToken(char[] array, int start, int end, int tokenType, int startOffset, boolean hyperlink) { + // This assumes all of your extra tokens would normally be scanned as IDENTIFIER. + int newType = pdeKeywords.getTokenType(array, start, end); + if (newType > -1) { + tokenType = newType; + } + super.addToken(array, start, end, tokenType, startOffset, hyperlink); + } + +} diff --git a/app/src/processing/app/syntax/SyntaxDocument.java b/app/src/processing/app/syntax/SyntaxDocument.java deleted file mode 100644 index 2a1c3103c..000000000 --- a/app/src/processing/app/syntax/SyntaxDocument.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * 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 - */ -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 deleted file mode 100644 index 23a7c71b0..000000000 --- a/app/src/processing/app/syntax/SyntaxStyle.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * 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 java.awt.font.TextAttribute; -import java.util.Hashtable; -import java.util.Map; - -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 - */ -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, boolean underlined) - { - this.color = color; - this.italic = italic; - this.bold = bold; - this.underlined = underlined; - } - - /** - * 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 || underlined); - } - - /** - * 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; - } - - /** - * @return true if underline is enabled for this style. - */ - public boolean isUnderlined() { - return underlined; - } - - /** - * Returns the specified font, but with the style's bold, underline 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()); - if (underlined) { - Map attr = new Hashtable(); - attr.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON); - lastStyledFont = lastStyledFont.deriveFont(attr); - } - 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()); - if (underlined) { - Map attr = new Hashtable(); - attr.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON); - lastStyledFont = lastStyledFont.deriveFont(attr); - } - //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" : "") + - (underlined ? ",underlined" : "") + - "]"; - } - - // private members - private Color color; - private boolean italic; - private boolean bold; - private boolean underlined; - 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 deleted file mode 100644 index 6eef977a0..000000000 --- a/app/src/processing/app/syntax/SyntaxUtilities.java +++ /dev/null @@ -1,226 +0,0 @@ -/* - * 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.*; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - - -/** - * Class with several utility functions used by jEdit's syntax colorizing - * subsystem. - * - * @author Slava Pestov - */ -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,false); - styles[Token.COMMENT2] = new SyntaxStyle(new Color(0x990033),true,false,false); - styles[Token.KEYWORD1] = new SyntaxStyle(Color.black,false,true,false); - styles[Token.KEYWORD2] = new SyntaxStyle(Color.magenta,false,false,false); - styles[Token.KEYWORD3] = new SyntaxStyle(new Color(0x009600),false,false,false); - styles[Token.LITERAL1] = new SyntaxStyle(new Color(0x650099),false,false,false); - styles[Token.LITERAL2] = new SyntaxStyle(new Color(0x650099),false,true,false); - styles[Token.LABEL] = new SyntaxStyle(new Color(0x990033),false,true,false); - styles[Token.OPERATOR] = new SyntaxStyle(Color.black,false,true,false); - styles[Token.URL] = new SyntaxStyle(Color.blue,true,false,false); - styles[Token.INVALID] = new SyntaxStyle(Color.red,false,true,false); - - 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(); - - 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; - if (id == Token.COMMENT1 || id == Token.COMMENT2) - x = drawTabbedCommentsText(line, x, y, gfx, expander, styles, styles[id]); - else - x = Utilities.drawTabbedText(line, x, y, gfx, expander, 0); - line.offset += length; - - tokens = tokens.next; - } - - return x; - } - - /** - * Parse comments and identify "@schematics <something>" pattern. - * - * @param line - * A string to parse - * @return null if the pattern is not found, otherwise an array of - * String is returned: the elements with index 0, 1 and 2 are - * respectively the preamble, the <something> stuff, and - * the remaining part of the string. - */ - public static String[] parseCommentUrls(String line) { - Matcher m = urlPattern.matcher(line.toString()); - if (!m.find()) - return null; - - String res[] = new String[3]; - res[0] = line.substring(0, m.start(1)); - res[1] = line.substring(m.start(1), m.end(1)); - res[2] = line.substring(m.end(1)); - // System.out.println("0 =>"+res[0]+"<\n1 =>"+res[1]+"< \n2 =>"+res[2]+"<"); - return res; - } - - static private Pattern urlPattern = Pattern.compile( - "((?:https?|ftp)://" + // ( Protocol - "(?:(?:[\\w_\\-]+:)?[\\w_\\-]+@)?" + // Username and password - "(?:[\\w_\\-]+\\.)+[\\w_\\-]+" + // Domain name - "(?::[0-9]{1,5})?" + // Port - "(?:/[\\w_\\-./?%&=+]*)?)" + // Path ) - "(?:\\s|$)"); // whitespace or EOL - - public static Segment stringToSegment(String v) { - return new Segment(v.toCharArray(), 0, v.length()); - } - - private static int drawTabbedCommentsText(Segment line, int x, int y, - Graphics gfx, TabExpander expander, SyntaxStyle[] styles, - SyntaxStyle commentStyle) { - - String parse[] = parseCommentUrls(line.toString()); - if (parse == null) - // Revert to plain writing. - return Utilities.drawTabbedText(line, x, y, gfx, expander, 0); - Segment pre = stringToSegment(parse[0]); - Segment tag = stringToSegment(parse[1]); - Segment post = stringToSegment(parse[2]); - - if (pre.count>0) - x = Utilities.drawTabbedText(pre, x, y, gfx, expander, 0); - - Font f = gfx.getFont(); - styles[Token.URL].setGraphicsFlags(gfx, f); - x = Utilities.drawTabbedText(tag, x, y, gfx, expander, 0); - - commentStyle.setGraphicsFlags(gfx, f); - if (post.count>0) - x = Utilities.drawTabbedText(post, x, y, gfx, expander, 0); - return x; - } - - // private members - private SyntaxUtilities() {} -} diff --git a/app/src/processing/app/syntax/TextAreaDefaults.java b/app/src/processing/app/syntax/TextAreaDefaults.java deleted file mode 100644 index c2e878578..000000000 --- a/app/src/processing/app/syntax/TextAreaDefaults.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * 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/TextAreaLineNumbers.java b/app/src/processing/app/syntax/TextAreaLineNumbers.java deleted file mode 100644 index 39f7438f2..000000000 --- a/app/src/processing/app/syntax/TextAreaLineNumbers.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * TextAreaLineNumbers.java - Show line numbers for the open file in the editor - * Copyright (C) 2013 Cayci Gorlitsky - * - * 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.Color; -import java.awt.Graphics; -import java.awt.Rectangle; - -import javax.swing.border.MatteBorder; - -public class TextAreaLineNumbers extends TextAreaPainter { - - private final int LEFT_INDENT = 6; - private final int RIGHT_INDENT = 6; - private final int RIGHT_BORDER_WIDTH = 1; - private final int PADDING_WIDTH = LEFT_INDENT + RIGHT_INDENT + RIGHT_BORDER_WIDTH; - - private final int MIN_WIDTH; - private final int DIGIT_WIDTH; - private final int MIN_NUM_DIGITS = 2; - - private int currStartNum = 0; - private int currEndNum = 0; - private int currNumDigits = MIN_NUM_DIGITS; - - - - public TextAreaLineNumbers(JEditTextArea textArea, TextAreaDefaults defaults) { - super(textArea, defaults); - DIGIT_WIDTH = getFontMetrics(getFont()).stringWidth("0"); - MIN_WIDTH = DIGIT_WIDTH * MIN_NUM_DIGITS + PADDING_WIDTH; - setEnabled(false); - setBorder(new MatteBorder(0, 0, 0, RIGHT_BORDER_WIDTH, new Color(240, 240, 240))); - } - - public void updateLineNumbers(int startNum, int endNum) { - if (currStartNum == startNum && currEndNum == endNum) { - return; - } - currStartNum = startNum; - currEndNum = endNum; - - invalidate(); - repaint(); - } - - @Override - public void paint(Graphics gfx) { - super.paint(gfx); - getBorder().paintBorder(this, gfx, 0, 0, getSize().width, getSize().height); - } - - @Override - protected void paintLine(Graphics gfx, TokenMarker tokenMarker, - int line, int x) - { - currentLineIndex = line; - gfx.setFont(getFont()); - gfx.setColor(Color.GRAY); - int y = textArea.lineToY(line); - int startX = getBounds().x + getBounds().width; - if (line >= 0 && line < textArea.getLineCount()) { - String lineNumberString = String.valueOf(line+1); - int lineStartX = startX - RIGHT_BORDER_WIDTH - RIGHT_INDENT - fm.stringWidth(lineNumberString); - gfx.drawString(lineNumberString,lineStartX,y + fm.getHeight()); - } - } - - public void updateWidthForNumDigits(int numDigits) { - if (currNumDigits == numDigits) { - return; - } - currNumDigits = numDigits; - - if (isVisible()) { - updateBounds(); - invalidate(); - repaint(); - } - } - - public void setDisplayLineNumbers(boolean displayLineNumbers) { - setVisible(displayLineNumbers); - if (displayLineNumbers) { - updateBounds(); - } else { - setBounds(new Rectangle(0, getHeight())); - } - invalidate(); - repaint(); - } - - private void updateBounds() { - if (isVisible()) { - setBounds(new Rectangle(Math.max(MIN_WIDTH, DIGIT_WIDTH * currNumDigits + PADDING_WIDTH), getHeight())); - textArea.validate(); - } - } -} diff --git a/app/src/processing/app/syntax/TextAreaPainter.java b/app/src/processing/app/syntax/TextAreaPainter.java deleted file mode 100644 index e99329526..000000000 --- a/app/src/processing/app/syntax/TextAreaPainter.java +++ /dev/null @@ -1,787 +0,0 @@ -/* -*- 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 processing.app.syntax.im.CompositionTextPainter; - -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; - /** Current setting for editor.antialias preference */ - boolean antialias; - - /** A specific painter composed by the InputMethod.*/ - protected CompositionTextPainter compositionTextPainter; - - /** - * 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); - - antialias = Preferences.getBoolean("editor.antialias"); - - 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; - } - - /** - * Get CompositionTextPainter. if CompositionTextPainter is not created, create it. - */ - public CompositionTextPainter getCompositionTextpainter(){ - if(compositionTextPainter == null){ - compositionTextPainter = new CompositionTextPainter(textArea); - } - return compositionTextPainter; - } - - /** - * 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) - { - Graphics2D g2 = (Graphics2D) gfx; - g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, - antialias ? - RenderingHints.VALUE_TEXT_ANTIALIAS_ON : - 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() - { - Dimension dim = new Dimension(); - dim.width = fm.charWidth('w') * 10; - dim.height = fm.getHeight() * 4; - return dim; - } - - // 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); - /* - * Draw characters via input method. - */ - if (compositionTextPainter != null && compositionTextPainter.hasComposedTextLayout()) { - compositionTextPainter.draw(gfx, lineHighlightColor); - } - 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); - /* - * Draw characters via input method. - */ - if (compositionTextPainter != null && compositionTextPainter.hasComposedTextLayout()) { - compositionTextPainter.draw(gfx, lineHighlightColor); - } - 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 deleted file mode 100644 index f009cd051..000000000 --- a/app/src/processing/app/syntax/TextUtilities.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * 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 - */ -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/TokenMarker.java b/app/src/processing/app/syntax/TokenMarker.java deleted file mode 100644 index 9244556d3..000000000 --- a/app/src/processing/app/syntax/TokenMarker.java +++ /dev/null @@ -1,341 +0,0 @@ -/* - * 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/im/CompositionTextManager.java b/app/src/processing/app/syntax/im/CompositionTextManager.java deleted file mode 100644 index ba9ee155f..000000000 --- a/app/src/processing/app/syntax/im/CompositionTextManager.java +++ /dev/null @@ -1,198 +0,0 @@ -package processing.app.syntax.im; - -import java.awt.Font; -import java.awt.FontMetrics; -import java.awt.Graphics2D; -import java.awt.Point; -import java.awt.Rectangle; -import java.awt.font.FontRenderContext; -import java.awt.font.TextAttribute; -import java.awt.font.TextLayout; -import java.text.AttributedCharacterIterator; -import java.text.AttributedString; - -import javax.swing.text.BadLocationException; - -import processing.app.syntax.JEditTextArea; -import processing.app.syntax.TextAreaPainter; - -/** - * This class Manage texts from input method - * by begin-process-end steps. - * - * First, if a user start inputing via input method, - * beginCompositionText is called from InputMethodSupport. - * Second, the user continues from input method, processCompositionText is called - * and reflect user inputs to text area. - * Finally the user try to commit text, endCompositionText is called. - * - * @author Takashi Maekawa (takachin@generative.info) - */ - -public class CompositionTextManager { - private JEditTextArea textArea; - private String prevComposeString; - private int prevCommittedCount; - private boolean isInputProcess; - private int initialCaretPosition; - public static final int COMPOSING_UNDERBAR_HEIGHT = 5; - - /** - * Create text manager class with a textarea. - * @param textArea texarea component for PDE. - */ - public CompositionTextManager(JEditTextArea textArea) { - this.textArea = textArea; - prevComposeString = ""; - isInputProcess = false; - prevCommittedCount = 0; - } - - /** - * Get this text manager is whether in input process or not. - */ - public boolean getIsInputProcess() { - return isInputProcess; - } - /** - * Insert full width space - */ - public void insertFullWidthSpace() { - initialCaretPosition = textArea.getCaretPosition(); - int layoutCaretPosition = initialCaretPosition; - try { - textArea.getDocument().insertString(layoutCaretPosition, "\u3000", null); - } catch (BadLocationException e) { - e.printStackTrace(); - } - } - - /** - * Called when a user begins input from input method. - * This method initializes text manager. - * - * @param text Text from InputMethodEvent. - * @param commited_count Numbers of committed characters in text. - */ - public void beginCompositionText(AttributedCharacterIterator text, int committed_count) { - isInputProcess = true; - prevComposeString = ""; - initialCaretPosition = textArea.getCaretPosition(); - processCompositionText(text, committed_count); - } - - /** - * Called when a user processing input characters and - * select candidates from input method. - * - * @param text Text from InputMethodEvent. - * @param commited_count Numbers of committed characters in text. - */ - public void processCompositionText(AttributedCharacterIterator text, int committed_count) { - int layoutCaretPosition = initialCaretPosition + committed_count; - CompositionTextPainter compositionPainter = textArea.getPainter().getCompositionTextpainter(); - compositionPainter.setComposedTextLayout(getTextLayout(text, committed_count), layoutCaretPosition); - int textLength = text.getEndIndex() - text.getBeginIndex() - committed_count; - StringBuffer unCommitedStringBuf = new StringBuffer(textLength); - char c; - for (c = text.setIndex(committed_count); c != AttributedCharacterIterator.DONE - && textLength > 0; c = text.next(), --textLength) { - unCommitedStringBuf.append(c); - } - String unCommittedString = unCommitedStringBuf.toString(); - try { - if(canRemovePreviousInput(committed_count)){ - textArea.getDocument().remove(layoutCaretPosition, prevComposeString.length()); - } - textArea.getDocument().insertString(layoutCaretPosition, unCommittedString, null); - if(committed_count > 0){ - initialCaretPosition = initialCaretPosition + committed_count; - } - prevComposeString = unCommittedString; - prevCommittedCount = committed_count; - } catch (BadLocationException e) { - e.printStackTrace(); - } - } - - private boolean canRemovePreviousInput(int committed_count){ - return (prevCommittedCount == committed_count || prevCommittedCount > committed_count); - } - - /** - * Called when a user fixed text from input method or delete all - * composition text. This method resets CompositionTextPainter. - * - * @param text Text from InputMethodEvent. - * @param commited_count Numbers of committed characters in text. - */ - public void endCompositionText(AttributedCharacterIterator text, int committed_count) { - /* - * If there are no committed characters, remove it all from textarea. - * This case will happen if a user delete all composing characters by backspace or delete key. - * If it does, these previous characters are needed to be deleted. - */ - if(committed_count == 0){ - removeNotCommittedText(text); - } - CompositionTextPainter compositionPainter = textArea.getPainter().getCompositionTextpainter(); - compositionPainter.invalidateComposedTextLayout(initialCaretPosition + committed_count); - prevComposeString = ""; - isInputProcess = false; - } - - private void removeNotCommittedText(AttributedCharacterIterator text){ - if (prevComposeString.length() == 0) { - return; - } - try { - textArea.getDocument().remove(initialCaretPosition, prevComposeString.length()); - } catch (BadLocationException e) { - e.printStackTrace(); - } - } - - private TextLayout getTextLayout(AttributedCharacterIterator text, int committed_count) { - AttributedString composed = new AttributedString(text, committed_count, text.getEndIndex()); - Font font = textArea.getPainter().getFont(); - FontRenderContext context = ((Graphics2D) (textArea.getPainter().getGraphics())).getFontRenderContext(); - composed.addAttribute(TextAttribute.FONT, font); - TextLayout layout = new TextLayout(composed.getIterator(), context); - return layout; - } - - private Point getCaretLocation() { - Point loc = new Point(); - TextAreaPainter painter = textArea.getPainter(); - FontMetrics fm = painter.getFontMetrics(); - int offsetY = fm.getHeight() - COMPOSING_UNDERBAR_HEIGHT; - int lineIndex = textArea.getCaretLine(); - loc.y = lineIndex * fm.getHeight() + offsetY; - int offsetX = textArea.getCaretPosition() - - textArea.getLineStartOffset(lineIndex); - loc.x = textArea.offsetToX(lineIndex, offsetX); - return loc; - } - - public Rectangle getTextLocation() { - Point caret = getCaretLocation(); - return getCaretRectangle(caret.x, caret.y); - } - - private Rectangle getCaretRectangle(int x, int y) { - TextAreaPainter painter = textArea.getPainter(); - Point origin = painter.getLocationOnScreen(); - int height = painter.getFontMetrics().getHeight(); - return new Rectangle(origin.x + x, origin.y + y, 0, height); - } - - public AttributedCharacterIterator getCommittedText(int beginIndex, int endIndex) { - int length = endIndex - beginIndex; - String textAreaString = textArea.getText(beginIndex, length); - return new AttributedString(textAreaString).getIterator(); - } - - public int getInsertPositionOffset() { - return textArea.getCaretPosition() * -1; - } -} diff --git a/app/src/processing/app/syntax/im/CompositionTextPainter.java b/app/src/processing/app/syntax/im/CompositionTextPainter.java deleted file mode 100644 index 0084f491f..000000000 --- a/app/src/processing/app/syntax/im/CompositionTextPainter.java +++ /dev/null @@ -1,124 +0,0 @@ -package processing.app.syntax.im; - -import java.awt.Color; -import java.awt.FontMetrics; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.Point; -import java.awt.font.TextLayout; - -import processing.app.syntax.JEditTextArea; -import processing.app.syntax.TextAreaPainter; - -/** - * Paint texts from input method. Text via input method are transmitted by - * AttributedCaharacterIterator. This class helps the PDE's TextAreaPainter - * to handle AttributedCaharacterIterator. - * - * For practical purposes, paint to textarea is done by TextLayout class. - * Because TextLayout class is easy to draw composing texts. (For example, - * draw underline composing texts, focus when select from candidates text.) - * - * @author Takashi Maekawa (takachin@generative.info) - */ -public class CompositionTextPainter { - private TextLayout composedTextLayout; - private int composedBeginCaretPosition = 0; - private JEditTextArea textArea; - - /** - * Constructor for painter. - * @param textarea textarea used by PDE. - */ - public CompositionTextPainter(JEditTextArea textArea) { - this.textArea = textArea; - composedTextLayout = null; - } - - /** - * Check the painter has TextLayout. - * If a user input via InputMethod, this result will return true. - * @param textarea textarea used by PDE. - */ - public boolean hasComposedTextLayout() { - return (composedTextLayout != null); - } - - /** - * Set TextLayout to the painter. - * TextLayout will be created and set by CompositionTextManager. - * - * @see CompositionTextManager - * @param textarea textarea used by PDE. - */ - public void setComposedTextLayout(TextLayout composedTextLayout, int composedStartCaretPosition) { - this.composedTextLayout = composedTextLayout; - this.composedBeginCaretPosition = composedStartCaretPosition; - } - - /** - * Invalidate this TextLayout to set null. - * If a user end input via InputMethod, this method will called from CompositionTextManager.endCompositionText - */ - public void invalidateComposedTextLayout(int composedEndCaretPosition) { - this.composedTextLayout = null; - this.composedBeginCaretPosition = composedEndCaretPosition; - //this.composedBeginCaretPosition = textArea.getCaretPosition(); - } - - /** - * Draw text via input method with composed text information. - * This method can draw texts with some underlines to illustrate converting characters. - * - * This method is workaround for TextAreaPainter. - * Because, TextAreaPainter can't treat AttributedCharacterIterator directly. - * AttributedCharacterIterator has very important information when composing text. - * It has a map where are converted characters and committed characters. - * Ideally, changing TextAreaPainter method can treat AttributedCharacterIterator is better. But it's very tough!! - * So I choose to write some code as a workaround. - * - * This draw method is proceeded with the following steps. - * 1. Original TextAreaPainter draws characters. - * 2. This refillComposedArea method erase previous paint characters by textarea's background color. - * The refill area is only square that width and height defined by characters with input method. - * 3. CompositionTextPainter.draw method paints composed text. It was actually drawn by TextLayout. - * - * @param gfx set TextAreaPainter's Graphics object. - * @param fillBackGroundColor set textarea's background. - */ - public void draw(Graphics gfx, Color fillBackGroundColor) { - assert(composedTextLayout != null); - Point composedLoc = getCaretLocation(); - refillComposedArea(fillBackGroundColor, composedLoc.x, composedLoc.y); - composedTextLayout.draw((Graphics2D) gfx, composedLoc.x, composedLoc.y); - } - - /** - * Fill color to erase characters drawn by original TextAreaPainter. - * - * @param fillColor fill color to erase characters drawn by original TextAreaPainter method. - * @param x x-coordinate where to fill. - * @param y y-coordinate where to fill. - */ - private void refillComposedArea(Color fillColor, int x, int y) { - Graphics gfx = textArea.getPainter().getGraphics(); - gfx.setColor(fillColor); - FontMetrics fm = textArea.getPainter().getFontMetrics(); - int newY = y - (fm.getHeight() - CompositionTextManager.COMPOSING_UNDERBAR_HEIGHT); - int paintHeight = fm.getHeight(); - int paintWidth = (int) composedTextLayout.getBounds().getWidth(); - gfx.fillRect(x, newY, paintWidth, paintHeight); - } - - private Point getCaretLocation() { - Point loc = new Point(); - TextAreaPainter painter = textArea.getPainter(); - FontMetrics fm = painter.getFontMetrics(); - int offsetY = fm.getHeight() - CompositionTextManager.COMPOSING_UNDERBAR_HEIGHT; - int lineIndex = textArea.getCaretLine(); - loc.y = lineIndex * fm.getHeight() + offsetY; - int offsetX = composedBeginCaretPosition - textArea.getLineStartOffset(lineIndex); - loc.x = textArea.offsetToX(lineIndex, offsetX); - return loc; - } -} diff --git a/app/src/processing/app/syntax/im/InputMethodSupport.java b/app/src/processing/app/syntax/im/InputMethodSupport.java deleted file mode 100644 index 461be3d16..000000000 --- a/app/src/processing/app/syntax/im/InputMethodSupport.java +++ /dev/null @@ -1,120 +0,0 @@ -package processing.app.syntax.im; - -import java.awt.Rectangle; -import java.awt.event.InputMethodEvent; -import java.awt.event.InputMethodListener; -import java.awt.font.TextHitInfo; -import java.awt.im.InputMethodRequests; -import java.text.AttributedCharacterIterator; - -import processing.app.syntax.JEditTextArea; - -/** - * Support in-line Japanese input for PDE. (Maybe Chinese, Korean and more) - * This class is implemented by Java Input Method Framework and handles - * If you would like to know more about Java Input Method Framework, - * Please see http://java.sun.com/j2se/1.5.0/docs/guide/imf/ - * - * This class is implemented to fix Bug #854. - * http://dev.processing.org/bugs/show_bug.cgi?id=854 - * - * @author Takashi Maekawa (takachin@generative.info) - */ -public class InputMethodSupport implements InputMethodRequests, - InputMethodListener { - - private int committed_count = 0; - private CompositionTextManager textManager; - - public InputMethodSupport(JEditTextArea textArea) { - textManager = new CompositionTextManager(textArea); - textArea.enableInputMethods(true); - textArea.addInputMethodListener(this); - } - - public Rectangle getTextLocation(TextHitInfo offset) { - return textManager.getTextLocation(); - } - - public TextHitInfo getLocationOffset(int x, int y) { - return null; - } - - public int getInsertPositionOffset() { - return textManager.getInsertPositionOffset(); - } - - public AttributedCharacterIterator getCommittedText(int beginIndex, - int endIndex, AttributedCharacterIterator.Attribute[] attributes) { - return textManager.getCommittedText(beginIndex, endIndex); - } - - public int getCommittedTextLength() { - return committed_count; - } - - public AttributedCharacterIterator cancelLatestCommittedText( - AttributedCharacterIterator.Attribute[] attributes) { - return null; - } - - public AttributedCharacterIterator getSelectedText( - AttributedCharacterIterator.Attribute[] attributes) { - return null; - } - - /** - * Handles events from InputMethod. - * This method judges whether beginning of input or - * progress of input or end and call related method. - * - * @param event event from Input Method. - */ - public void inputMethodTextChanged(InputMethodEvent event) { - AttributedCharacterIterator text = event.getText(); - committed_count = event.getCommittedCharacterCount(); - if(isFullWidthSpaceInput(text)){ - textManager.insertFullWidthSpace(); - caretPositionChanged(event); - return; - } - if(isBeginInputProcess(text, textManager)){ - textManager.beginCompositionText(text, committed_count); - caretPositionChanged(event); - return; - } - if (isInputProcess(text)){ - textManager.processCompositionText(text, committed_count); - caretPositionChanged(event); - return; - } - textManager.endCompositionText(text, committed_count); - caretPositionChanged(event); - } - - private boolean isFullWidthSpaceInput(AttributedCharacterIterator text){ - if(text == null) - return false; - if(textManager.getIsInputProcess()) - return false; - return (String.valueOf(text.first()).equals("\u3000")); - } - - private boolean isBeginInputProcess(AttributedCharacterIterator text, CompositionTextManager textManager){ - if(text == null) - return false; - if(textManager.getIsInputProcess()) - return false; - return (isInputProcess(text)); - } - - private boolean isInputProcess(AttributedCharacterIterator text){ - if(text == null) - return false; - return (text.getEndIndex() - (text.getBeginIndex() + committed_count) > 0); - } - - public void caretPositionChanged(InputMethodEvent event) { - event.consume(); - } -} diff --git a/app/src/processing/app/syntax/readme.txt b/app/src/processing/app/syntax/readme.txt deleted file mode 100644 index 07a825cd7..000000000 --- a/app/src/processing/app/syntax/readme.txt +++ /dev/null @@ -1,46 +0,0 @@ -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/AutoFormat.java b/app/src/processing/app/tools/AutoFormat.java index 572ea692c..f855400b1 100644 --- a/app/src/processing/app/tools/AutoFormat.java +++ b/app/src/processing/app/tools/AutoFormat.java @@ -440,7 +440,7 @@ public class AutoFormat implements Tool { // Adding an additional newline as a hack around other errors String originalText = editor.getText() + "\n"; strOut = new StringBuffer(); - indentValue = Preferences.getInteger("editor.tabs.size"); + indentValue = PreferencesData.getInteger("editor.tabs.size"); indentChar = new String(" "); lineNumber = 0; diff --git a/app/src/processing/app/tools/DiscourseFormat.java b/app/src/processing/app/tools/DiscourseFormat.java index a4a381c5a..75240cb69 100644 --- a/app/src/processing/app/tools/DiscourseFormat.java +++ b/app/src/processing/app/tools/DiscourseFormat.java @@ -25,11 +25,14 @@ package processing.app.tools; import java.awt.*; import java.awt.datatransfer.*; + +import javax.swing.text.BadLocationException; import javax.swing.text.Segment; +import org.fife.ui.rsyntaxtextarea.Token; + import processing.app.*; import processing.app.syntax.*; -import processing.app.legacy.PApplet; /** * Format for Discourse Tool @@ -44,6 +47,8 @@ import processing.app.legacy.PApplet; *

* Updated for 0144 to only format the selected lines. *

+ * Updated for 1.5.8 - Simplification, using RSyntaxTextArea TokenImpl formatter (08 dec 2014 - Ricardo JL Rufino) + *

* Notes from the original source: * Discourse.java This is a dirty-mix source. * NOTE that: No macs and no keyboard. Unreliable source. @@ -54,7 +59,7 @@ public class DiscourseFormat { private Editor editor; // JTextArea of the actual Editor - private JEditTextArea textarea; + private SketchTextArea textarea; private boolean html; @@ -78,10 +83,16 @@ public class DiscourseFormat { StringBuilder cf = new StringBuilder(html ? "

\n" : "[code]\n");
 
     int selStart = textarea.getSelectionStart();
-    int selStop = textarea.getSelectionStop();
+    int selStop = textarea.getSelectionEnd();
 
-    int startLine = textarea.getSelectionStartLine();
-    int stopLine = textarea.getSelectionStopLine();
+    int startLine;
+    int stopLine;
+    try {
+      startLine = textarea.getLineOfOffset(selStart);
+      stopLine = textarea.getLineOfOffset(selStop);
+    } catch (BadLocationException e) {
+      return;
+    }
 
     // If no selection, convert all the lines
     if (selStart == selStop) {
@@ -89,8 +100,11 @@ public class DiscourseFormat {
       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--;
+      try {
+        if (textarea.getLineStartOffset(stopLine) == selStop) {
+          stopLine--;
+        }
+      } catch (BadLocationException e) {
       }
     }
 
@@ -139,23 +153,15 @@ public class DiscourseFormat {
   public void appendFormattedLine(StringBuilder 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);
-
+    textarea.getTextLine(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) {
+    if (!html) {
       for (int j = 0; j < segmentCount; j++) {
         char c = segmentArray[j + segmentOffset];
         appendToHTML(c, cf);
@@ -169,82 +175,19 @@ public class DiscourseFormat {
       }
 
     } 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) {
-            appendToHTML(c, cf);
-          } else {
-            cf.append('\n');
-          }
-          return; // cf.toString();
-        }
-        if (id == Token.NULL) {
-//          fm = painter.getFontMetrics();
-        } else {
-          // Place open tags []
-          if (html) {
-            cf.append("");
-          }
-
-          if (html && styles[id].isBold())
-            cf.append("");
-
-//          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(html ? " " : '\u00A0');  //  
-//            if ((j % 2) == 1) {
-//              cf.append("[b]\u00A0[/b]");
-//            } else {
-//              cf.append(' ');
-//            }
-          } else {
-            appendToHTML(c, cf);
-          }
-          // Place close tags [/]
-          if (html && j == (length - 1) && id != Token.NULL && styles[id].isBold())
-            cf.append("");
-          if (html && j == (length - 1) && id != Token.NULL)
-            cf.append("");
-//          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;
+      
+      Token tokenList = textarea.getTokenListForLine(line);
+      
+      while(tokenList != null){
+        if(tokenList.getType() == Token.NULL){
+          cf.append('\n');
+        }else if(tokenList.isPaintable()){
+          tokenList.appendHTMLRepresentation(cf, textarea, false);
+        }
+        
+        tokenList = tokenList.getNextToken();
       }
+  
     }
   }
 }
diff --git a/app/test/cc/arduino/packages/contributions/GPGDetachedSignatureVerifierTest.java b/app/test/cc/arduino/packages/contributions/GPGDetachedSignatureVerifierTest.java
new file mode 100644
index 000000000..c4b4c8633
--- /dev/null
+++ b/app/test/cc/arduino/packages/contributions/GPGDetachedSignatureVerifierTest.java
@@ -0,0 +1,66 @@
+/*
+ * This file is part of Arduino.
+ *
+ * Copyright 2015 Arduino LLC (http://www.arduino.cc/)
+ *
+ * Arduino 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction.  Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License.  This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ */
+
+package cc.arduino.packages.contributions;
+
+import cc.arduino.contributions.GPGDetachedSignatureVerifier;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.File;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class GPGDetachedSignatureVerifierTest {
+
+  private GPGDetachedSignatureVerifier GPGDetachedSignatureVerifier;
+
+  @Before
+  public void setUp() throws Exception {
+    GPGDetachedSignatureVerifier = new GPGDetachedSignatureVerifier();
+  }
+
+  @Test
+  public void testSignatureSuccessfulVerification() throws Exception {
+    File signedFile = new File(GPGDetachedSignatureVerifierTest.class.getResource("./package_index.json").getFile());
+    File sign = new File(GPGDetachedSignatureVerifierTest.class.getResource("./package_index.json.sig").getFile());
+    File publickKey = new File(GPGDetachedSignatureVerifierTest.class.getResource("./public.gpg.key").getFile());
+    assertTrue(GPGDetachedSignatureVerifier.verify(signedFile, sign, publickKey));
+  }
+
+  @Test
+  public void testSignatureFailingVerification() throws Exception {
+    File fakeSignedFile = File.createTempFile("fakeSigned", "txt");
+    fakeSignedFile.deleteOnExit();
+    File sign = new File(GPGDetachedSignatureVerifierTest.class.getResource("./package_index.json.sig").getFile());
+    File publickKey = new File(GPGDetachedSignatureVerifierTest.class.getResource("./public.gpg.key").getFile());
+    assertFalse(GPGDetachedSignatureVerifier.verify(fakeSignedFile, sign, publickKey));
+  }
+}
diff --git a/app/test/cc/arduino/packages/contributions/HostDependentDownloadableContributionStub.java b/app/test/cc/arduino/packages/contributions/HostDependentDownloadableContributionStub.java
new file mode 100644
index 000000000..b751d261f
--- /dev/null
+++ b/app/test/cc/arduino/packages/contributions/HostDependentDownloadableContributionStub.java
@@ -0,0 +1,65 @@
+/*
+ * This file is part of Arduino.
+ *
+ * Copyright 2015 Arduino LLC (http://www.arduino.cc/)
+ *
+ * Arduino 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction.  Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License.  This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ */
+
+package cc.arduino.packages.contributions;
+
+import cc.arduino.contributions.packages.HostDependentDownloadableContribution;
+
+public class HostDependentDownloadableContributionStub extends HostDependentDownloadableContribution {
+
+  @Override
+  public String getVersion() {
+    return null;
+  }
+
+  @Override
+  public String getHost() {
+    return null;
+  }
+
+  @Override
+  public String getUrl() {
+    return null;
+  }
+
+  @Override
+  public String getChecksum() {
+    return null;
+  }
+
+  @Override
+  public long getSize() {
+    return 0;
+  }
+
+  @Override
+  public String getArchiveFileName() {
+    return null;
+  }
+}
diff --git a/app/test/cc/arduino/packages/contributions/HostDependentDownloadableContributionTest.java b/app/test/cc/arduino/packages/contributions/HostDependentDownloadableContributionTest.java
new file mode 100644
index 000000000..8174f26d6
--- /dev/null
+++ b/app/test/cc/arduino/packages/contributions/HostDependentDownloadableContributionTest.java
@@ -0,0 +1,112 @@
+/*
+ * This file is part of Arduino.
+ *
+ * Copyright 2015 Arduino LLC (http://www.arduino.cc/)
+ *
+ * Arduino 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction.  Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License.  This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ */
+
+package cc.arduino.packages.contributions;
+
+import org.junit.Test;
+import processing.app.Platform;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class HostDependentDownloadableContributionTest {
+
+  @Test
+  public void macOsXPositiveTest() {
+    HostDependentDownloadableContributionStub contribution = new HostDependentDownloadableContributionStub() {
+      @Override
+      public String getHost() {
+        return "x86_64-apple-darwin";
+      }
+    };
+
+    Platform platform = new Platform() {
+      @Override
+      public String getOsName() {
+        return "Mac OS X";
+      }
+
+      @Override
+      public String getOsArch() {
+        return "x86_64";
+      }
+    };
+
+    assertTrue(contribution.isCompatible(platform));
+  }
+
+  @Test
+  public void macOsXNegativeTest() {
+    HostDependentDownloadableContributionStub contribution = new HostDependentDownloadableContributionStub() {
+      @Override
+      public String getHost() {
+        return "x86_64-apple-darwin";
+      }
+    };
+
+    Platform platform = new Platform() {
+      @Override
+      public String getOsName() {
+        return "Linux";
+      }
+
+      @Override
+      public String getOsArch() {
+        return "amd64";
+      }
+    };
+
+    assertFalse(contribution.isCompatible(platform));
+  }
+
+  @Test
+  public void macOsXNegativeTest2() {
+    HostDependentDownloadableContributionStub contribution = new HostDependentDownloadableContributionStub() {
+      @Override
+      public String getHost() {
+        return "x86_64-apple-darwin";
+      }
+    };
+
+    Platform platform = new Platform() {
+      @Override
+      public String getOsName() {
+        return "Mac OS X";
+      }
+
+      @Override
+      public String getOsArch() {
+        return "i686";
+      }
+    };
+
+    assertFalse(contribution.isCompatible(platform));
+  }
+
+}
diff --git a/app/test/cc/arduino/packages/contributions/package_index.json b/app/test/cc/arduino/packages/contributions/package_index.json
new file mode 100644
index 000000000..7b0cb6781
--- /dev/null
+++ b/app/test/cc/arduino/packages/contributions/package_index.json
@@ -0,0 +1,757 @@
+{
+  "packages": [
+    {
+      "name": "arduino",
+      "maintainer": "Arduino",
+      "websiteURL": "http://www.arduino.cc/",
+      "email": "packages@arduino.cc",
+      "help": {
+        "online": "http://arduino.cc/en/Reference/HomePage"
+      },
+      "platforms": [
+        {
+          "name": "Arduino AVR Boards",
+          "architecture": "avr",
+          "version": "1.6.2",
+          "category": "Arduino",
+          "url": "http://downloads.arduino.cc/cores/avr-1.6.2.tar.bz2",
+          "archiveFileName": "avr-1.6.2.tar.bz2",
+          "checksum": "SHA-256:2909a4c6dd6d7497e7e1b5fcaa2f66a100271417510f3a68593b65af8ff78c1c",
+          "size": "4877442",
+          "boards": [
+            {"name": "Arduino Yún"},
+            {"name": "Arduino Uno"},
+            {"name": "Arduino Diecimila"},
+            {"name": "Arduino Nano"},
+            {"name": "Arduino Mega"},
+            {"name": "Arduino MegaADK"},
+            {"name": "Arduino Leonardo"},
+            {"name": "Arduino Micro"},
+            {"name": "Arduino Esplora"},
+            {"name": "Arduino Mini"},
+            {"name": "Arduino Ethernet"},
+            {"name": "Arduino Fio"},
+            {"name": "Arduino BT"},
+            {"name": "Arduino LilyPadUSB"},
+            {"name": "Arduino Lilypad"},
+            {"name": "Arduino Pro"},
+            {"name": "Arduino ATMegaNG"},
+            {"name": "Arduino Robot Control"},
+            {"name": "Arduino Robot Motor"}
+          ],
+          "toolsDependencies": [
+            {
+              "packager": "arduino",
+              "name": "avr-gcc",
+              "version": "4.8.1-arduino2"
+            },
+            {
+              "packager": "arduino",
+              "name": "avrdude",
+              "version": "6.0.1-arduino2"
+            }
+          ]
+        },
+        {
+          "name": "Arduino AVR Boards",
+          "architecture": "avr",
+          "version": "1.6.3",
+          "category": "Arduino",
+          "help": {
+            "online": "http://arduino.cc/en/Reference/HomePage"
+          },
+          "url": "http://downloads.arduino.cc/cores/avr-1.6.3.tar.bz2",
+          "archiveFileName": "avr-1.6.3.tar.bz2",
+          "checksum": "SHA-256:c30033ba70cbb2d46ee0901a331b0f83be082f9110eda0464b624fdbb51b3c7b",
+          "size": "4876816",
+          "boards": [
+            {"name": "Arduino Yún"},
+            {"name": "Arduino Uno"},
+            {"name": "Arduino Diecimila"},
+            {"name": "Arduino Nano"},
+            {"name": "Arduino Mega"},
+            {"name": "Arduino MegaADK"},
+            {"name": "Arduino Leonardo"},
+            {"name": "Arduino Micro"},
+            {"name": "Arduino Esplora"},
+            {"name": "Arduino Mini"},
+            {"name": "Arduino Ethernet"},
+            {"name": "Arduino Fio"},
+            {"name": "Arduino BT"},
+            {"name": "Arduino LilyPadUSB"},
+            {"name": "Arduino Lilypad"},
+            {"name": "Arduino Pro"},
+            {"name": "Arduino ATMegaNG"},
+            {"name": "Arduino Robot Control"},
+            {"name": "Arduino Robot Motor"}
+          ],
+          "toolsDependencies": [
+            {
+              "packager": "arduino",
+              "name": "avr-gcc",
+              "version": "4.8.1-arduino3"
+            },
+            {
+              "packager": "arduino",
+              "name": "avrdude",
+              "version": "6.0.1-arduino3"
+            }
+          ]
+        },
+        {
+          "name": "Arduino AVR Boards",
+          "architecture": "avr",
+          "version": "1.6.4",
+          "category": "Arduino",
+          "help": {
+            "online": "http://arduino.cc/en/Reference/HomePage"
+          },
+          "url": "http://downloads.arduino.cc/cores/avr-1.6.4.tar.bz2",
+          "archiveFileName": "avr-1.6.4.tar.bz2",
+          "checksum": "SHA-256:8a243410aeded6dbcbc4b134ba10be5c2562d137bfcf3ac97abdc5844933b363",
+          "size": "4780884",
+          "boards": [
+            {"name": "Arduino Yún"},
+            {"name": "Arduino Uno"},
+            {"name": "Arduino Diecimila"},
+            {"name": "Arduino Nano"},
+            {"name": "Arduino Mega"},
+            {"name": "Arduino MegaADK"},
+            {"name": "Arduino Leonardo"},
+            {"name": "Arduino Micro"},
+            {"name": "Arduino Esplora"},
+            {"name": "Arduino Mini"},
+            {"name": "Arduino Ethernet"},
+            {"name": "Arduino Fio"},
+            {"name": "Arduino BT"},
+            {"name": "Arduino LilyPadUSB"},
+            {"name": "Arduino Lilypad"},
+            {"name": "Arduino Pro"},
+            {"name": "Arduino ATMegaNG"},
+            {"name": "Arduino Robot Control"},
+            {"name": "Arduino Robot Motor"}
+          ],
+          "toolsDependencies": [
+            {
+              "packager": "arduino",
+              "name": "avr-gcc",
+              "version": "4.8.1-arduino5"
+            },
+            {
+              "packager": "arduino",
+              "name": "avrdude",
+              "version": "6.0.1-arduino5"
+            }
+          ]
+        },
+        {
+          "name": "Arduino AVR Boards",
+          "architecture": "avr",
+          "version": "1.6.5",
+          "category": "Arduino",
+          "help": {
+            "online": "http://arduino.cc/en/Reference/HomePage"
+          },
+          "url": "http://downloads.arduino.cc/cores/avr-1.6.5.tar.bz2",
+          "archiveFileName": "avr-1.6.5.tar.bz2",
+          "checksum": "SHA-256:c72d890aa605add677634c6b25ebc3b2ed9e44c38805b95c47eab17a1ca72db6",
+          "size": "4876957",
+          "boards": [
+            {"name": "Arduino Yún"},
+            {"name": "Arduino Uno"},
+            {"name": "Arduino Diecimila"},
+            {"name": "Arduino Nano"},
+            {"name": "Arduino Mega"},
+            {"name": "Arduino MegaADK"},
+            {"name": "Arduino Leonardo"},
+            {"name": "Arduino Micro"},
+            {"name": "Arduino Esplora"},
+            {"name": "Arduino Mini"},
+            {"name": "Arduino Ethernet"},
+            {"name": "Arduino Fio"},
+            {"name": "Arduino BT"},
+            {"name": "Arduino LilyPadUSB"},
+            {"name": "Arduino Lilypad"},
+            {"name": "Arduino Pro"},
+            {"name": "Arduino ATMegaNG"},
+            {"name": "Arduino Robot Control"},
+            {"name": "Arduino Robot Motor"}
+          ],
+          "toolsDependencies": [
+            {
+              "packager": "arduino",
+              "name": "avr-gcc",
+              "version": "4.8.1-arduino5"
+            },
+            {
+              "packager": "arduino",
+              "name": "avrdude",
+              "version": "6.0.1-arduino5"
+            }
+          ]
+        },
+        {
+          "name": "Arduino AVR Boards",
+          "architecture": "avr",
+          "version": "1.6.6",
+          "category": "Arduino",
+          "help": {
+            "online": "http://arduino.cc/en/Reference/HomePage"
+          },
+          "url": "http://downloads.arduino.cc/cores/avr-1.6.6.tar.bz2",
+          "archiveFileName": "avr-1.6.6.tar.bz2",
+          "checksum": "SHA-256:08ad5db4978ebea22344edc5d77dce0923d8a644da7a14dc8072e883c76058d8",
+          "size": "4876916",
+          "boards": [
+            {"name": "Arduino Yún"},
+            {"name": "Arduino Uno"},
+            {"name": "Arduino Diecimila"},
+            {"name": "Arduino Nano"},
+            {"name": "Arduino Mega"},
+            {"name": "Arduino MegaADK"},
+            {"name": "Arduino Leonardo"},
+            {"name": "Arduino Micro"},
+            {"name": "Arduino Esplora"},
+            {"name": "Arduino Mini"},
+            {"name": "Arduino Ethernet"},
+            {"name": "Arduino Fio"},
+            {"name": "Arduino BT"},
+            {"name": "Arduino LilyPadUSB"},
+            {"name": "Arduino Lilypad"},
+            {"name": "Arduino Pro"},
+            {"name": "Arduino ATMegaNG"},
+            {"name": "Arduino Robot Control"},
+            {"name": "Arduino Robot Motor"}
+          ],
+          "toolsDependencies": [
+            {
+              "packager": "arduino",
+              "name": "avr-gcc",
+              "version": "4.8.1-arduino5"
+            },
+            {
+              "packager": "arduino",
+              "name": "avrdude",
+              "version": "6.0.1-arduino5"
+            }
+          ]
+        },
+        {
+          "name": "Arduino SAM Boards (32-bits ARM Cortex-M3)",
+          "architecture": "sam",
+          "version": "1.6.2",
+          "category": "Arduino",
+          "url": "http://downloads.arduino.cc/cores/sam-1.6.2.tar.bz2",
+          "archiveFileName": "sam-1.6.2.tar.bz2",
+          "checksum": "SHA-256:2d3c8a90bc214947cff1b816d0c2706441398efc78af7984d5250f2e50eddd5f",
+          "size": "16174730",
+          "boards": [
+            {"name": "Arduino Due"}
+          ],
+          "toolsDependencies": [
+            {
+              "packager": "arduino",
+              "name": "arm-none-eabi-gcc",
+              "version": "4.8.3-2014q1"
+            },
+            {
+              "packager": "arduino",
+              "name": "bossac",
+              "version": "1.3a-arduino"
+            }
+          ]
+        },
+        {
+          "name": "Arduino SAM Boards (32-bits ARM Cortex-M3)",
+          "architecture": "sam",
+          "version": "1.6.3",
+          "category": "Arduino",
+          "url": "http://downloads.arduino.cc/cores/sam-1.6.3.tar.bz2",
+          "archiveFileName": "sam-1.6.3.tar.bz2",
+          "checksum": "SHA-256:0a6e1d5542790e38ba454c796aabbd0e48b07635a5b4d8adc044a4eba959ca27",
+          "size": "16174017",
+          "boards": [
+            {"name": "Arduino Due"}
+          ],
+          "toolsDependencies": [
+            {
+              "packager": "arduino",
+              "name": "arm-none-eabi-gcc",
+              "version": "4.8.3-2014q1"
+            },
+            {
+              "packager": "arduino",
+              "name": "bossac",
+              "version": "1.3a-arduino"
+            }
+          ]
+        },
+        {
+          "name": "Arduino SAM Boards (32-bits ARM Cortex-M3)",
+          "architecture": "sam",
+          "version": "1.6.4",
+          "category": "Arduino",
+          "url": "http://downloads.arduino.cc/cores/sam-1.6.4.tar.bz2",
+          "archiveFileName": "sam-1.6.4.tar.bz2",
+          "checksum": "SHA-256:e0dc94d8ad0756b79838e99ad7409b08b07e40ed667ebe86eae11644ef7bec0d",
+          "size": "16174992",
+          "boards": [
+            {"name": "Arduino Due"}
+          ],
+          "toolsDependencies": [
+            {
+              "packager": "arduino",
+              "name": "arm-none-eabi-gcc",
+              "version": "4.8.3-2014q1"
+            },
+            {
+              "packager": "arduino",
+              "name": "bossac",
+              "version": "1.3a-arduino"
+            }
+          ]
+        }
+      ],
+      "tools": [
+        {
+          "name": "arm-none-eabi-gcc",
+          "version": "4.8.3-2014q1",
+          "systems": [
+            {
+              "host": "i686-mingw32",
+              "archiveFileName": "gcc-arm-none-eabi-4.8.3-2014q1-windows.tar.gz",
+              "url": "http://downloads.arduino.cc/gcc-arm-none-eabi-4.8.3-2014q1-windows.tar.gz",
+              "checksum": "SHA-256:fd8c111c861144f932728e00abd3f7d1107e186eb9cd6083a54c7236ea78b7c2",
+              "size": "84537449"
+            },
+            {
+              "host": "x86_64-apple-darwin",
+              "url": "http://downloads.arduino.cc/gcc-arm-none-eabi-4.8.3-2014q1-mac.tar.gz",
+              "archiveFileName": "gcc-arm-none-eabi-4.8.3-2014q1-mac.tar.gz",
+              "checksum": "SHA-256:3598acf21600f17a8e4a4e8e193dc422b894dc09384759b270b2ece5facb59c2",
+              "size": "52518522"
+            },
+            {
+              "host": "x86_64-pc-linux-gnu",
+              "url": "http://downloads.arduino.cc/gcc-arm-none-eabi-4.8.3-2014q1-linux64.tar.gz",
+              "archiveFileName": "gcc-arm-none-eabi-4.8.3-2014q1-linux64.tar.gz",
+              "checksum": "SHA-256:d23f6626148396d6ec42a5b4d928955a703e0757829195fa71a939e5b86eecf6",
+              "size": "51395093"
+            },
+            {
+              "host": "i686-pc-linux-gnu",
+              "url": "http://downloads.arduino.cc/gcc-arm-none-eabi-4.8.3-2014q1-linux32.tar.gz",
+              "archiveFileName": "gcc-arm-none-eabi-4.8.3-2014q1-linux32.tar.gz",
+              "checksum": "SHA-256:ba1994235f69c526c564f65343f22ddbc9822b2ea8c5ee07dd79d89f6ace2498",
+              "size": "51029223"
+            }
+          ]
+        },
+        {
+          "name": "bossac",
+          "version": "1.3a-arduino",
+          "systems": [
+            {
+              "host": "i686-linux-gnu",
+              "url": "http://downloads.arduino.cc/tools/bossac-1.3a-arduino-i686-linux-gnu.tar.bz2",
+              "archiveFileName": "bossac-1.3a-arduino-i686-linux-gnu.tar.bz2",
+              "checksum": "SHA-256:d6d10362f40729a7877e43474fcf02ad82cf83321cc64ca931f5c82b2d25d24f",
+              "size": "147359"
+            },
+            {
+              "host": "x86_64-pc-linux-gnu",
+              "url": "http://downloads.arduino.cc/tools/bossac-1.3a-arduino-x86_64-pc-linux-gnu.tar.bz2",
+              "archiveFileName": "bossac-1.3a-arduino-x86_64-pc-linux-gnu.tar.bz2",
+              "checksum": "SHA-256:c1daed033251296768fa8b63ad283e053da93427c0f3cd476a71a9188e18442c",
+              "size": "26179"
+            },
+            {
+              "host": "i686-mingw32",
+              "url": "http://downloads.arduino.cc/tools/bossac-1.3a-arduino-i686-mingw32.tar.bz2",
+              "archiveFileName": "bossac-1.3a-arduino-i686-mingw32.tar.bz2",
+              "checksum": "SHA-256:a37727622e0f86cb4f2856ad0209568a5d804234dba3dc0778829730d61a5ec7",
+              "size": "265647"
+            },
+            {
+              "host": "i386-apple-darwin11",
+              "url": "http://downloads.arduino.cc/tools/bossac-1.3a-arduino-i386-apple-darwin11.tar.bz2",
+              "archiveFileName": "bossac-1.3a-arduino-i386-apple-darwin11.tar.bz2",
+              "checksum": "SHA-256:40770b225753e7a52bb165e8f37e6b760364f5c5e96048168d0178945bd96ad6",
+              "size": "39475"
+            }
+          ]
+        },
+        {
+          "name": "avr-gcc",
+          "version": "4.8.1-arduino2",
+          "systems": [
+            {
+              "size": "24443285",
+              "checksum": "SHA-256:c19a7526235c364d7f62ec1a993d9b495973ba1813869ccf0241c65905896852",
+              "host": "i386-apple-darwin11",
+              "archiveFileName": "avr-gcc-4.8.1-arduino2-i386-apple-darwin11.tar.bz2",
+              "url": "http://downloads.arduino.cc/tools/avr-gcc-4.8.1-arduino2-i386-apple-darwin11.tar.bz2"
+            },
+            {
+              "size": "27152002",
+              "checksum": "SHA-256:24a931877bee5f36dc00a88877219a6d2f6a1fb7abb989fd04556b8432d2e14e",
+              "host": "x86_64-linux-gnu",
+              "archiveFileName": "avr-gcc-4.8.1-arduino2-x86_64-pc-linux-gnu.tar.bz2",
+              "url": "http://downloads.arduino.cc/tools/avr-gcc-4.8.1-arduino2-x86_64-pc-linux-gnu.tar.bz2"
+            },
+            {
+              "size": "25876628",
+              "checksum": "SHA-256:2d701b4efbc8cec62dc299cde01730c5eebcf23d7e4393db8cf7744a9bf1d3de",
+              "host": "i686-linux-gnu",
+              "archiveFileName": "avr-gcc-4.8.1-arduino2-i686-pc-linux-gnu.tar.bz2",
+              "url": "http://downloads.arduino.cc/tools/avr-gcc-4.8.1-arduino2-i686-pc-linux-gnu.tar.bz2"
+            },
+            {
+              "size": "46046691",
+              "checksum": "SHA-256:2eafb49fb803fa4d2c32d35e24c0b372fcd520ca0a790fa537a847179e382000",
+              "host": "i686-mingw32",
+              "archiveFileName": "avr-gcc-4.8.1-arduino2-i686-mingw32.zip",
+              "url": "http://downloads.arduino.cc/tools/avr-gcc-4.8.1-arduino2-i686-mingw32.zip"
+            }
+          ]
+        },
+        {
+          "name": "avrdude",
+          "version": "6.0.1-arduino2",
+          "systems": [
+            {
+              "size": "264965",
+              "checksum": "SHA-256:71117cce0096dad6c091e2c34eb0b9a3386d3aec7d863d2da733d9e5eac3a6b1",
+              "host": "i386-apple-darwin11",
+              "archiveFileName": "avrdude-6.0.1-arduino2-i386-apple-darwin11.tar.bz2",
+              "url": "http://downloads.arduino.cc/tools/avrdude-6.0.1-arduino2-i386-apple-darwin11.tar.bz2"
+            },
+            {
+              "size": "292541",
+              "checksum": "SHA-256:2489004d1d98177eaf69796760451f89224007c98b39ebb5577a9a34f51425f1",
+              "host": "x86_64-linux-gnu",
+              "archiveFileName": "avrdude-6.0.1-arduino2-x86_64-pc-linux-gnu.tar.bz2",
+              "url": "http://downloads.arduino.cc/tools/avrdude-6.0.1-arduino2-x86_64-pc-linux-gnu.tar.bz2"
+            },
+            {
+              "size": "283209",
+              "checksum": "SHA-256:6f633dd6270ad0d9ef19507bcbf8697b414a15208e4c0f71deec25ef89cdef3f",
+              "host": "i686-linux-gnu",
+              "archiveFileName": "avrdude-6.0.1-arduino2-i686-pc-linux-gnu.tar.bz2",
+              "url": "http://downloads.arduino.cc/tools/avrdude-6.0.1-arduino2-i686-pc-linux-gnu.tar.bz2"
+            },
+            {
+              "size": "241618",
+              "checksum": "SHA-256:6c5483800ba753c80893607e30cade8ab77b182808fcc5ea15fa3019c63d76ae",
+              "host": "i686-mingw32",
+              "archiveFileName": "avrdude-6.0.1-arduino2-i686-mingw32.zip",
+              "url": "http://downloads.arduino.cc/tools/avrdude-6.0.1-arduino2-i686-mingw32.zip"
+            }
+          ]
+        },
+        {
+          "name": "avr-gcc",
+          "version": "4.8.1-arduino3",
+          "systems": [
+            {
+              "size": "24447175",
+              "checksum": "SHA-256:28e207c66b3dc405367d0c5e68ce3c278e5ec3abb0e4974e7927fe0f9a532c40",
+              "host": "i386-apple-darwin11",
+              "archiveFileName": "avr-gcc-4.8.1-arduino3-i386-apple-darwin11.tar.bz2",
+              "url": "http://downloads.arduino.cc/tools/avr-gcc-4.8.1-arduino3-i386-apple-darwin11.tar.bz2"
+            },
+            {
+              "size": "30556996",
+              "checksum": "SHA-256:028340abec6eb3085b82404dfc7ed143e1bb05b2da961b539ddcdba4a6f65533",
+              "host": "x86_64-linux-gnu",
+              "archiveFileName": "avr-gcc-4.8.1-arduino3-x86_64-pc-linux-gnu.tar.bz2",
+              "url": "http://downloads.arduino.cc/tools/avr-gcc-4.8.1-arduino3-x86_64-pc-linux-gnu.tar.bz2"
+            },
+            {
+              "size": "28768022",
+              "checksum": "SHA-256:37796548ba9653267568f959cd8c7ebfe5b4bce4599898cf9f876d64e616cb87",
+              "host": "i686-linux-gnu",
+              "archiveFileName": "avr-gcc-4.8.1-arduino3-i686-pc-linux-gnu.tar.bz2",
+              "url": "http://downloads.arduino.cc/tools/avr-gcc-4.8.1-arduino3-i686-pc-linux-gnu.tar.bz2"
+            },
+            {
+              "size": "46046917",
+              "checksum": "SHA-256:d6f0527793f9800f060408392a99eb290ed205730edbae43a1a25cbf6b6b588f",
+              "host": "i686-mingw32",
+              "archiveFileName": "avr-gcc-4.8.1-arduino3-i686-mingw32.zip",
+              "url": "http://downloads.arduino.cc/tools/avr-gcc-4.8.1-arduino3-i686-mingw32.zip"
+            }
+          ]
+        },
+        {
+          "name": "avrdude",
+          "version": "6.0.1-arduino3",
+          "systems": [
+            {
+              "size": "264682",
+              "checksum": "SHA-256:df7cd4a76e45ab3767eb964f845f4d5e9d643df950ec32812923da1e9843d072",
+              "host": "i386-apple-darwin11",
+              "archiveFileName": "avrdude-6.0.1-arduino3-i386-apple-darwin11.tar.bz2",
+              "url": "http://downloads.arduino.cc/tools/avrdude-6.0.1-arduino3-i386-apple-darwin11.tar.bz2"
+            },
+            {
+              "size": "748634",
+              "checksum": "SHA-256:bb7bff48f20a68e1fe559c3f3f644574df12ab5c98eb6a1491079f3c760434ad",
+              "host": "x86_64-linux-gnu",
+              "archiveFileName": "avrdude-6.0.1-arduino3-x86_64-pc-linux-gnu.tar.bz2",
+              "url": "http://downloads.arduino.cc/tools/avrdude-6.0.1-arduino3-x86_64-pc-linux-gnu.tar.bz2"
+            },
+            {
+              "size": "495482",
+              "checksum": "SHA-256:96a0cfb83fe0452366159e3bf4e19ff10906a8957d1feafd3d98b49ab4b14405",
+              "host": "i686-linux-gnu",
+              "archiveFileName": "avrdude-6.0.1-arduino3-i686-pc-linux-gnu.tar.bz2",
+              "url": "http://downloads.arduino.cc/tools/avrdude-6.0.1-arduino3-i686-pc-linux-gnu.tar.bz2"
+            },
+            {
+              "size": "241619",
+              "checksum": "SHA-256:ea59bfc2ee85039c85318b2ba52c47ef0573513444a785b72f59b22586a950f9",
+              "host": "i686-mingw32",
+              "archiveFileName": "avrdude-6.0.1-arduino3-i686-mingw32.zip",
+              "url": "http://downloads.arduino.cc/tools/avrdude-6.0.1-arduino3-i686-mingw32.zip"
+            }
+          ]
+        },
+        {
+          "name": "avr-gcc",
+          "version": "4.8.1-arduino5",
+          "systems": [
+            {
+              "size": "24437400",
+              "checksum": "SHA-256:111b3ef00d737d069eb237a8933406cbb928e4698689e24663cffef07688a901",
+              "host": "i386-apple-darwin11",
+              "archiveFileName": "avr-gcc-4.8.1-arduino5-i386-apple-darwin11.tar.bz2",
+              "url": "http://downloads.arduino.cc/tools/avr-gcc-4.8.1-arduino5-i386-apple-darwin11.tar.bz2"
+            },
+            {
+              "size": "27093036",
+              "checksum": "SHA-256:9054fcc174397a419ba56c4ce1bfcbcad275a6a080cc144905acc9b0351ee9cc",
+              "host": "x86_64-linux-gnu",
+              "archiveFileName": "avr-gcc-4.8.1-arduino5-x86_64-pc-linux-gnu.tar.bz2",
+              "url": "http://downloads.arduino.cc/tools/avr-gcc-4.8.1-arduino5-x86_64-pc-linux-gnu.tar.bz2"
+            },
+            {
+              "size": "25882375",
+              "checksum": "SHA-256:7648b7f549b37191da0b0be53bae791b652f82ac3cb4e7877f85075aaf32141f",
+              "host": "i686-linux-gnu",
+              "archiveFileName": "avr-gcc-4.8.1-arduino5-i686-pc-linux-gnu.tar.bz2",
+              "url": "http://downloads.arduino.cc/tools/avr-gcc-4.8.1-arduino5-i686-pc-linux-gnu.tar.bz2"
+            },
+            {
+              "size": "46044779",
+              "checksum": "SHA-256:d4303226a7b41d3c445d901b5aa5903458def3fc7b7ff4ffef37cabeb37d424d",
+              "host": "i686-mingw32",
+              "archiveFileName": "avr-gcc-4.8.1-arduino5-i686-mingw32.zip",
+              "url": "http://downloads.arduino.cc/tools/avr-gcc-4.8.1-arduino5-i686-mingw32.zip"
+            }
+          ]
+        },
+        {
+          "name": "avrdude",
+          "version": "6.0.1-arduino5",
+          "systems": [
+            {
+              "size": "264894",
+              "checksum": "SHA-256:41af8d3b0a586853c8317b4fb5163ca0db594a1870ddf680fd988c42166fc3e5",
+              "host": "i386-apple-darwin11",
+              "archiveFileName": "avrdude-6.0.1-arduino5-i386-apple-darwin11.tar.bz2",
+              "url": "http://downloads.arduino.cc/tools/avrdude-6.0.1-arduino5-i386-apple-darwin11.tar.bz2"
+            },
+            {
+              "size": "292629",
+              "checksum": "SHA-256:d826cca7383461f7e8adde686372cf900e9cb3afd639555cf2d6c645b283a476",
+              "host": "x86_64-linux-gnu",
+              "archiveFileName": "avrdude-6.0.1-arduino5-x86_64-pc-linux-gnu.tar.bz2",
+              "url": "http://downloads.arduino.cc/tools/avrdude-6.0.1-arduino5-x86_64-pc-linux-gnu.tar.bz2"
+            },
+            {
+              "size": "283121",
+              "checksum": "SHA-256:5933d66927bce46ababa9b68a8b7f1d53f68c4f3ff7a5ce4b85d7cf4e6c6bfee",
+              "host": "i686-linux-gnu",
+              "archiveFileName": "avrdude-6.0.1-arduino5-i686-pc-linux-gnu.tar.bz2",
+              "url": "http://downloads.arduino.cc/tools/avrdude-6.0.1-arduino5-i686-pc-linux-gnu.tar.bz2"
+            },
+            {
+              "size": "241634",
+              "checksum": "SHA-256:41f667f1f6a0ab8df46b4ffacd023176dcdef331d6db3b74bddd37d18cca0a44",
+              "host": "i686-mingw32",
+              "archiveFileName": "avrdude-6.0.1-arduino5-i686-mingw32.zip",
+              "url": "http://downloads.arduino.cc/tools/avrdude-6.0.1-arduino5-i686-mingw32.zip"
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "email": "support@intel.com",
+      "maintainer": "Intel",
+      "websiteURL": "http://www.intel.com/",
+      "name": "Intel",
+      "platforms": [
+        {
+          "name": "Intel i586 Boards",
+          "version": "1.6.2+1.0",
+          "category": "Arduino Certified",
+          "architecture": "i586",
+          "url": "https://github.com/01org/corelibs-galileo/archive/1.6.2+1.0.tar.gz",
+          "archiveFileName": "corelibs-galileo-1.6.2.tar.gz",
+          "checksum": "SHA-256:e20d62b0dccf0d68dbb61d70b866d77134b770b226d6046a61c7e8d55e64e53a",
+          "size": "272961",
+          "boards": [
+            {
+              "name": "Galileo"
+            }
+          ],
+          "toolsDependencies": [
+            {
+              "packager": "Intel",
+              "name": "i586-poky-linux-uclibc",
+              "version": "1.6.2+1.0"
+            },
+            {
+              "packager": "Intel",
+              "name": "sketchUploader",
+              "version": "1.6.2+1.0"
+            }
+          ]
+        },
+        {
+          "name": "Intel i686 Boards",
+          "version": "1.6.2+1.0",
+          "category": "Arduino Certified",
+          "architecture": "i686",
+          "url": "https://github.com/01org/corelibs-edison/archive/1.6.2+1.0.tar.gz",
+          "archiveFileName": "corelibs-edison-1.6.2.tar.gz",
+          "checksum": "SHA-256:538ab8553f832f56b04df80d44992ecc994b9c296f3fce6902832d97f99811a8",
+          "size": "271420",
+          "boards": [
+            {
+              "name": "Edison"
+            }
+          ],
+          "toolsDependencies": [
+            {
+              "packager": "Intel",
+              "name": "core2-32-poky-linux",
+              "version": "1.6.2+1.0"
+            },
+            {
+              "packager": "Intel",
+              "name": "sketchUploader",
+              "version": "1.6.2+1.0"
+            }
+          ]
+        }
+      ],
+      "tools": [
+        {
+          "name": "i586-poky-linux-uclibc",
+          "version": "1.6.2+1.0",
+          "systems": [
+            {
+              "size": "30587705",
+              "checksum": "SHA-256:5b705d26dc1d8ca8953df6e0c08dcc8584d5be77b584d561f631360fd166677c",
+              "host": "i386-apple-darwin11",
+              "archiveFileName": "galileo-toolchain-20150323-osx.tar.bz2",
+              "url": "http://downloadmirror.intel.com/24806/eng/galileo-toolchain-osx-1.6.2-1.0.tar.bz2"
+            },
+            {
+              "size": "45948648",
+              "checksum": "SHA-256:821eb290d7c668c1caa74da30903c13843edc746d41508b35161622ae6279b56",
+              "host": "i686-mingw32",
+              "archiveFileName": "galileo-toolchain-20150323-windows.zip",
+              "url": "http://downloadmirror.intel.com/24806/eng/galileo-toolchain-windows-1.6.2-1.0.zip"
+            },
+            {
+              "size": "56227185",
+              "checksum": "SHA-256:935ccad3eaaec34f5de76eceb0f0ecd1372bdab0b7dc8f4241e8260c6f827b72",
+              "host": "x86_64-linux-gnu",
+              "archiveFileName": "galileo-toolchain-20150316-linux64.tar.bz2",
+              "url": "http://downloadmirror.intel.com/24806/eng/galileo-toolchain-linux64-1.6.2-1.0.tar.bz2"
+            },
+            {
+              "size": "55098166",
+              "checksum": "SHA-256:1dab7f21e10d0208a6dd2897c36c6f5f55f9372b947225d2b59c3c4ab4777d03",
+              "host": "i686-linux-gnu",
+              "archiveFileName": "galileo-toolchain-20150316-linux32.tar.bz2",
+              "url": "http://downloadmirror.intel.com/24806/eng/galileo-toolchain-linux32-1.6.2-1.0.tar.bz2"
+            }
+          ]
+        },
+        {
+          "name": "core2-32-poky-linux",
+          "version": "1.6.2+1.0",
+          "systems": [
+            {
+              "size": "42720934",
+              "checksum": "SHA-256:fac0b3f00a33ee0531ea0da6d517c170409e25bd5e59f6f3db9506974336375d",
+              "host": "i386-apple-darwin11",
+              "archiveFileName": "edison-toolchain-20150323-osx.tar.bz2",
+              "url": "http://downloadmirror.intel.com/24806/eng/edison-toolchain-osx-1.6.2-1.0.tar.bz2"
+            },
+            {
+              "size": "56683094",
+              "checksum": "SHA-256:5a9a1b51f0fa18bf21e1dcf1332d34331dd435c5ca0d1fe008e68e13cb3255e5",
+              "host": "i686-mingw32",
+              "archiveFileName": "edison-toolchain-20150323-windows.zip",
+              "url": "http://downloadmirror.intel.com/24806/eng/edison-toolchain-windows-1.6.2-1.0.zip"
+            },
+            {
+              "size": "78998436",
+              "checksum": "SHA-256:e3443e7832732f2189fd424e4868d2ebb563e823addb2321a6e8a86a9fced193",
+              "host": "x86_64-linux-gnu",
+              "archiveFileName": "edison-toolchain-20150316-linux64.tar.bz2",
+              "url": "http://downloadmirror.intel.com/24806/eng/edison-toolchain-linux64-1.6.2-1.0.tar.bz2"
+            },
+            {
+              "size": "76488215",
+              "checksum": "SHA-256:014d1bdc40bb080987c736d04ffd42cdc0d2c3cad001891fb01555dac04296f7",
+              "host": "i686-linux-gnu",
+              "archiveFileName": "edison-toolchain-20150316-linux32.tar.bz2",
+              "url": "http://downloadmirror.intel.com/24806/eng/edison-toolchain-linux32-1.6.2-1.0.tar.bz2"
+            }
+          ]
+        },
+        {
+          "name": "sketchUploader",
+          "version": "1.6.2+1.0",
+          "systems": [
+            {
+              "size": "61789",
+              "checksum": "SHA-256:8395ccb57c627f997fe01170df4613de906f48c6ce99623b9ca42806079c28ad",
+              "host": "i386-apple-darwin11",
+              "archiveFileName": "intel-arduino-tools-20150316-osx.tar.gz",
+              "url": "https://github.com/01org/intel-arduino-tools/archive/1.6.2+1.0-osx.tar.gz"
+            },
+            {
+              "size": "2534586",
+              "checksum": "SHA-256:47f0b1558653d09f6f1e5d21a9cdef379be96c9147711cf54f013f73e4deed11",
+              "host": "i686-mingw32",
+              "archiveFileName": "intel-arduino-tools-20150316-windows.zip",
+              "url": "https://github.com/01org/intel-arduino-tools/archive/1.6.2+1.0-windows.zip"
+            },
+            {
+              "size": "178239",
+              "checksum": "SHA-256:2876db4153db22609d2f6c9c3bfb198efbb9d9574edad579aca7d58cff9d2cca",
+              "host": "x86_64-linux-gnu",
+              "archiveFileName": "intel-arduino-tools-20150316-linux64.tar.gz",
+              "url": "https://github.com/01org/intel-arduino-tools/archive/1.6.2+1.0-linux64.tar.gz"
+            },
+            {
+              "size": "187995",
+              "checksum": "SHA-256:20d87602d0194be626f592d3f2bdc9566a5a897786b042393482ef4c26ae158c",
+              "host": "i686-linux-gnu",
+              "archiveFileName": "intel-arduino-tools-20150316-linux32.tar.gz",
+              "url": "https://github.com/01org/intel-arduino-tools/archive/1.6.2+1.0-linux32.tar.gz"
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/app/test/cc/arduino/packages/contributions/package_index.json.sig b/app/test/cc/arduino/packages/contributions/package_index.json.sig
new file mode 100644
index 000000000..10c7ff659
Binary files /dev/null and b/app/test/cc/arduino/packages/contributions/package_index.json.sig differ
diff --git a/app/test/cc/arduino/packages/contributions/public.gpg.key b/app/test/cc/arduino/packages/contributions/public.gpg.key
new file mode 100644
index 000000000..5de39fed1
Binary files /dev/null and b/app/test/cc/arduino/packages/contributions/public.gpg.key differ
diff --git a/app/test/processing/app/AbstractGUITest.java b/app/test/processing/app/AbstractGUITest.java
index b5a209bb0..b4fe19db0 100644
--- a/app/test/processing/app/AbstractGUITest.java
+++ b/app/test/processing/app/AbstractGUITest.java
@@ -1,5 +1,35 @@
+/*
+ * This file is part of Arduino.
+ *
+ * Copyright 2015 Arduino LLC (http://www.arduino.cc/)
+ *
+ * Arduino 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction.  Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License.  This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ */
+
 package processing.app;
 
+import cc.arduino.files.DeleteFilesOnShutdown;
 import org.fest.swing.edt.FailOnThreadViolationRepaintManager;
 import org.fest.swing.edt.GuiActionRunner;
 import org.fest.swing.edt.GuiQuery;
@@ -15,6 +45,9 @@ public abstract class AbstractGUITest {
 
   @Before
   public void startUpTheIDE() throws Exception {
+    System.setProperty("mrj.version", "whynot"); //makes sense only on osx. See https://github.com/alexruiz/fest-swing-1.x/issues/2#issuecomment-86532042
+    Runtime.getRuntime().addShutdownHook(new Thread(DeleteFilesOnShutdown.INSTANCE));
+
     FailOnThreadViolationRepaintManager.install();
 
     Base.initPlatform();
@@ -23,7 +56,7 @@ public abstract class AbstractGUITest {
     Theme.init();
     Base.getPlatform().setLookAndFeel();
     Base.untitledFolder = Base.createTempFolder("untitled");
-    Base.untitledFolder.deleteOnExit();
+    DeleteFilesOnShutdown.add(Base.untitledFolder);
 
     window = GuiActionRunner.execute(new GuiQuery() {
       @Override
diff --git a/app/test/processing/app/AbstractWithPreferencesTest.java b/app/test/processing/app/AbstractWithPreferencesTest.java
index ca07ec385..7ee6e2195 100644
--- a/app/test/processing/app/AbstractWithPreferencesTest.java
+++ b/app/test/processing/app/AbstractWithPreferencesTest.java
@@ -1,17 +1,51 @@
+/*
+ * This file is part of Arduino.
+ *
+ * Copyright 2015 Arduino LLC (http://www.arduino.cc/)
+ *
+ * Arduino 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction.  Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License.  This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ */
+
 package processing.app;
 
+import cc.arduino.files.DeleteFilesOnShutdown;
 import org.junit.Before;
 
 public abstract class AbstractWithPreferencesTest {
 
   @Before
   public void init() throws Exception {
+    Runtime.getRuntime().addShutdownHook(new Thread(DeleteFilesOnShutdown.INSTANCE));
     Base.initPlatform();
+    Base.getPlatform().init();
     Preferences.init(null);
     Theme.init();
 
-    Base.untitledFolder = Base.createTempFolder("untitled");
-    Base.untitledFolder.deleteOnExit();
+    BaseNoGui.initPackages();
 
+    Base.untitledFolder = Base.createTempFolder("untitled");
+    DeleteFilesOnShutdown.add(Base.untitledFolder);
   }
+
 }
diff --git a/app/test/processing/app/AutoformatProducesOneUndoActionTest.java b/app/test/processing/app/AutoformatProducesOneUndoActionTest.java
new file mode 100644
index 000000000..8c5243a66
--- /dev/null
+++ b/app/test/processing/app/AutoformatProducesOneUndoActionTest.java
@@ -0,0 +1,85 @@
+/*
+ * This file is part of Arduino.
+ *
+ * Copyright 2015 Arduino LLC
+ *
+ * Arduino 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction.  Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License.  This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ */
+
+package processing.app;
+
+import org.fest.swing.fixture.JMenuItemFixture;
+import org.junit.Test;
+import processing.app.helpers.SketchTextAreaFixture;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+public class AutoformatProducesOneUndoActionTest extends AbstractGUITest {
+
+  public static final String SOURCE_BEFORE = "void setup() {\n" +
+          "              // put your setup code here, to run once:\n" +
+          "\n" +
+          "}\n" +
+          "\n" +
+          "void loop() {\n" +
+          "  // put your main code here, to run repeatedly:\n" +
+          "\n" +
+          "}";
+  public static final String SOURCE_AFTER = "void setup() {\n" +
+          "  // put your setup code here, to run once:\n" +
+          "\n" +
+          "}\n" +
+          "\n" +
+          "void loop() {\n" +
+          "  // put your main code here, to run repeatedly:\n" +
+          "\n" +
+          "}";
+
+  @Test
+  public void shouldSaveCaretPositionAfterAutoformat() {
+    JMenuItemFixture menuEditUndo = window.menuItem("menuEditUndo");
+    menuEditUndo.requireDisabled();
+
+    JMenuItemFixture menuToolsAutoFormat = window.menuItem("menuToolsAutoFormat");
+    menuToolsAutoFormat.requireEnabled();
+
+    SketchTextAreaFixture editor = window.textArea("editor");
+    editor.setText(SOURCE_BEFORE);
+
+    editor.setCaretPosition(29); // right before the first // (double slash)
+
+    menuToolsAutoFormat.click();
+
+    String formattedText = editor.getText();
+    assertEquals(SOURCE_AFTER, formattedText);
+
+    assertEquals(29, editor.getCaretPosition());
+
+    menuEditUndo.requireEnabled();
+    menuEditUndo.click();
+    assertEquals(SOURCE_BEFORE, editor.getText());
+  }
+
+}
diff --git a/app/test/processing/app/AutoformatSavesCaretPositionTest.java b/app/test/processing/app/AutoformatSavesCaretPositionTest.java
index 8ffa03190..fb311707d 100644
--- a/app/test/processing/app/AutoformatSavesCaretPositionTest.java
+++ b/app/test/processing/app/AutoformatSavesCaretPositionTest.java
@@ -1,8 +1,37 @@
+/*
+ * This file is part of Arduino.
+ *
+ * Copyright 2015 Arduino LLC (http://www.arduino.cc/)
+ *
+ * Arduino 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction.  Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License.  This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ */
+
 package processing.app;
 
 import org.fest.swing.fixture.JMenuItemFixture;
 import org.junit.Test;
-import processing.app.helpers.JEditTextAreaFixture;
+import processing.app.helpers.SketchTextAreaFixture;
 
 import static org.junit.Assert.assertEquals;
 
@@ -13,7 +42,7 @@ public class AutoformatSavesCaretPositionTest extends AbstractGUITest {
     JMenuItemFixture menuToolsAutoFormat = window.menuItem("menuToolsAutoFormat");
     menuToolsAutoFormat.requireEnabled();
 
-    JEditTextAreaFixture editor = window.jEditTextArea("editor");
+    SketchTextAreaFixture editor = window.textArea("editor");
     editor.setText("void setup() {\n" +
             "              // put your setup code here, to run once:\n" +
             "\n" +
diff --git a/app/test/processing/app/AutoformatTest.java b/app/test/processing/app/AutoformatTest.java
index 51fdc35d6..2b87b1757 100644
--- a/app/test/processing/app/AutoformatTest.java
+++ b/app/test/processing/app/AutoformatTest.java
@@ -1,8 +1,37 @@
+/*
+ * This file is part of Arduino.
+ *
+ * Copyright 2015 Arduino LLC (http://www.arduino.cc/)
+ *
+ * Arduino 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction.  Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License.  This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ */
+
 package processing.app;
 
 import org.fest.swing.fixture.JMenuItemFixture;
 import org.junit.Test;
-import processing.app.helpers.JEditTextAreaFixture;
+import processing.app.helpers.SketchTextAreaFixture;
 
 import static org.junit.Assert.assertEquals;
 
@@ -13,7 +42,7 @@ public class AutoformatTest extends AbstractGUITest {
     JMenuItemFixture menuToolsAutoFormat = window.menuItem("menuToolsAutoFormat");
     menuToolsAutoFormat.requireEnabled();
 
-    JEditTextAreaFixture editor = window.jEditTextArea("editor");
+    SketchTextAreaFixture editor = window.textArea("editor");
     editor.setText("void setup() {\n" +
             "// put your setup code here, to run once:\n" +
             "int foo[] = { 1, 2, 3, 4, 5};\n" +
diff --git a/app/test/processing/app/BlockCommentGeneratesOneUndoActionTest.java b/app/test/processing/app/BlockCommentGeneratesOneUndoActionTest.java
index 555a03fcc..411cb5de6 100644
--- a/app/test/processing/app/BlockCommentGeneratesOneUndoActionTest.java
+++ b/app/test/processing/app/BlockCommentGeneratesOneUndoActionTest.java
@@ -1,14 +1,44 @@
+/*
+ * This file is part of Arduino.
+ *
+ * Copyright 2015 Arduino LLC (http://www.arduino.cc/)
+ *
+ * Arduino 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction.  Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License.  This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ */
+
 package processing.app;
 
+import static org.junit.Assert.assertEquals;
+
+import java.awt.Frame;
+
 import org.fest.swing.edt.GuiActionRunner;
 import org.fest.swing.edt.GuiQuery;
 import org.fest.swing.fixture.JMenuItemFixture;
 import org.junit.Test;
-import processing.app.helpers.JEditTextAreaFixture;
 
-import java.awt.*;
-
-import static org.junit.Assert.assertEquals;
+import processing.app.helpers.SketchTextAreaFixture;
 
 public class BlockCommentGeneratesOneUndoActionTest extends AbstractGUITest {
 
@@ -17,7 +47,7 @@ public class BlockCommentGeneratesOneUndoActionTest extends AbstractGUITest {
     JMenuItemFixture menuEditUndo = window.menuItem("menuEditUndo");
     menuEditUndo.requireDisabled();
 
-    JEditTextAreaFixture jEditTextArea = window.jEditTextArea("editor");
+    SketchTextAreaFixture jEditTextArea = window.textArea("editor");
     String previousText = jEditTextArea.getText();
 
     jEditTextArea.selectAll();
diff --git a/app/test/processing/app/DefaultTargetTest.java b/app/test/processing/app/DefaultTargetTest.java
index e2641e36a..37819c84c 100644
--- a/app/test/processing/app/DefaultTargetTest.java
+++ b/app/test/processing/app/DefaultTargetTest.java
@@ -1,3 +1,32 @@
+/*
+ * This file is part of Arduino.
+ *
+ * Copyright 2015 Arduino LLC (http://www.arduino.cc/)
+ *
+ * Arduino 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction.  Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License.  This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ */
+
 package processing.app;
 
 import org.junit.After;
@@ -14,18 +43,18 @@ public class DefaultTargetTest extends AbstractWithPreferencesTest {
 
   @Before
   public void saveBoardFromPreferences() throws Exception {
-    oldBoardID = Preferences.get("board");
+    oldBoardID = PreferencesData.get("board");
   }
 
   @After
   public void restoreBoardIntoPreferences() throws Exception {
-    Preferences.set("board", oldBoardID);
-    Preferences.save();
+    PreferencesData.set("board", oldBoardID);
+    PreferencesData.save();
   }
 
   @Test
   public void testDefaultTarget() throws Exception {
-    Preferences.set("board", "unreal_board");
+    PreferencesData.set("board", "unreal_board");
 
     // should not raise an exception
     new Base(new String[0]);
diff --git a/app/test/processing/app/HittingEscapeOnCloseConfirmationDialogTest.java b/app/test/processing/app/HittingEscapeOnCloseConfirmationDialogTest.java
index c760ef29b..b56559659 100644
--- a/app/test/processing/app/HittingEscapeOnCloseConfirmationDialogTest.java
+++ b/app/test/processing/app/HittingEscapeOnCloseConfirmationDialogTest.java
@@ -1,10 +1,39 @@
+/*
+ * This file is part of Arduino.
+ *
+ * Copyright 2015 Arduino LLC (http://www.arduino.cc/)
+ *
+ * Arduino 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction.  Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License.  This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ */
+
 package processing.app;
 
 import org.fest.swing.core.KeyPressInfo;
 import org.fest.swing.finder.WindowFinder;
 import org.fest.swing.fixture.DialogFixture;
 import org.junit.Test;
-import processing.app.helpers.JEditTextAreaFixture;
+import processing.app.helpers.SketchTextAreaFixture;
 
 import javax.swing.*;
 import java.awt.event.KeyEvent;
@@ -15,7 +44,7 @@ public class HittingEscapeOnCloseConfirmationDialogTest extends AbstractGUITest
 
   @Test
   public void shouldJustCloseTheDialog() throws Exception {
-    JEditTextAreaFixture editor = window.jEditTextArea("editor");
+    SketchTextAreaFixture editor = window.textArea("editor");
     editor.setText("test");
 
     window.close();
diff --git a/app/test/processing/app/I18NTest.java b/app/test/processing/app/I18NTest.java
index 74c231ef7..1df455f91 100644
--- a/app/test/processing/app/I18NTest.java
+++ b/app/test/processing/app/I18NTest.java
@@ -1,3 +1,32 @@
+/*
+ * This file is part of Arduino.
+ *
+ * Copyright 2015 Arduino LLC (http://www.arduino.cc/)
+ *
+ * Arduino 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction.  Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License.  This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ */
+
 package processing.app;
 
 import org.junit.Ignore;
diff --git a/app/test/processing/app/ReduceIndentWith1CharOnLastLineTest.java b/app/test/processing/app/ReduceIndentWith1CharOnLastLineTest.java
index 9ee7e0c50..f5cd01f89 100644
--- a/app/test/processing/app/ReduceIndentWith1CharOnLastLineTest.java
+++ b/app/test/processing/app/ReduceIndentWith1CharOnLastLineTest.java
@@ -1,3 +1,32 @@
+/*
+ * This file is part of Arduino.
+ *
+ * Copyright 2015 Arduino LLC (http://www.arduino.cc/)
+ *
+ * Arduino 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction.  Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License.  This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ */
+
 package processing.app;
 
 import static org.junit.Assert.assertEquals;
@@ -5,7 +34,7 @@ import static org.junit.Assert.assertEquals;
 import org.fest.swing.fixture.JMenuItemFixture;
 import org.junit.Test;
 
-import processing.app.helpers.JEditTextAreaFixture;
+import processing.app.helpers.SketchTextAreaFixture;
 
 public class ReduceIndentWith1CharOnLastLineTest extends AbstractGUITest {
 
@@ -13,7 +42,7 @@ public class ReduceIndentWith1CharOnLastLineTest extends AbstractGUITest {
   public void shouldJustCloseTheDialog() throws Exception {
     JMenuItemFixture menuDecreaseIndent = window.menuItem("menuDecreaseIndent");
 
-    JEditTextAreaFixture editor = window.jEditTextArea("editor");
+    SketchTextAreaFixture editor = window.textArea("editor");
     editor.setText("void loop()\n{\n  Serial.begin(9600)\n}");
 
     editor.selectAll();
diff --git a/app/test/processing/app/ReplacingTextGeneratesTwoUndoActionsTest.java b/app/test/processing/app/ReplacingTextGeneratesTwoUndoActionsTest.java
index bd03f1108..f1ebe4a97 100644
--- a/app/test/processing/app/ReplacingTextGeneratesTwoUndoActionsTest.java
+++ b/app/test/processing/app/ReplacingTextGeneratesTwoUndoActionsTest.java
@@ -1,8 +1,37 @@
+/*
+ * This file is part of Arduino.
+ *
+ * Copyright 2015 Arduino LLC (http://www.arduino.cc/)
+ *
+ * Arduino 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction.  Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License.  This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ */
+
 package processing.app;
 
 import org.fest.swing.fixture.JMenuItemFixture;
 import org.junit.Test;
-import processing.app.helpers.JEditTextAreaFixture;
+import processing.app.helpers.SketchTextAreaFixture;
 
 import static org.junit.Assert.assertEquals;
 
@@ -15,19 +44,19 @@ public class ReplacingTextGeneratesTwoUndoActionsTest extends AbstractGUITest {
     JMenuItemFixture menuEditRedo = window.menuItem("menuEditRedo");
     menuEditRedo.requireDisabled();
 
-    JEditTextAreaFixture jEditTextArea = window.jEditTextArea("editor");
+    SketchTextAreaFixture textArea = window.textArea("editor");
 
-    jEditTextArea.setText("fake text");
+    textArea.setText("fake text");
 
     menuEditUndo.requireEnabled();
     menuEditUndo.click();
 
-    assertEquals("", jEditTextArea.getText());
+    assertEquals("", textArea.getText());
 
     menuEditRedo.requireEnabled();
     menuEditRedo.click();
 
-    //assertEquals("fake text", jEditTextArea.getText());
+    //assertEquals("fake text", RSyntaxTextArea.getText());
 
     menuEditUndo.requireEnabled();
     menuEditUndo.click();
diff --git a/app/test/processing/app/TestHelper.java b/app/test/processing/app/TestHelper.java
index bee55b09e..ae433061d 100644
--- a/app/test/processing/app/TestHelper.java
+++ b/app/test/processing/app/TestHelper.java
@@ -1,3 +1,32 @@
+/*
+ * This file is part of Arduino.
+ *
+ * Copyright 2015 Arduino LLC (http://www.arduino.cc/)
+ *
+ * Arduino 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction.  Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License.  This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ */
+
 package processing.app;
 
 import java.io.*;
diff --git a/app/test/processing/app/debug/CompilerTest.java b/app/test/processing/app/debug/CompilerTest.java
index 1d701ff64..9662df24a 100755
--- a/app/test/processing/app/debug/CompilerTest.java
+++ b/app/test/processing/app/debug/CompilerTest.java
@@ -1,3 +1,32 @@
+/*
+ * This file is part of Arduino.
+ *
+ * Copyright 2015 Arduino LLC (http://www.arduino.cc/)
+ *
+ * Arduino 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction.  Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License.  This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ */
+
 package processing.app.debug;
 
 import static org.junit.Assert.assertEquals;
diff --git a/app/test/processing/app/debug/TargetPlatformStub.java b/app/test/processing/app/debug/TargetPlatformStub.java
new file mode 100644
index 000000000..a8048c514
--- /dev/null
+++ b/app/test/processing/app/debug/TargetPlatformStub.java
@@ -0,0 +1,102 @@
+/*
+ * This file is part of Arduino.
+ *
+ * Copyright 2015 Arduino LLC (http://www.arduino.cc/)
+ *
+ * Arduino 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction.  Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License.  This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ */
+
+package processing.app.debug;
+
+import processing.app.helpers.PreferencesMap;
+
+import java.io.File;
+import java.util.Map;
+import java.util.Set;
+
+public class TargetPlatformStub implements TargetPlatform {
+
+  private final String id;
+  private final TargetPackage targetPackage;
+
+  public TargetPlatformStub(String id, TargetPackage targetPackage) {
+    this.id = id;
+    this.targetPackage = targetPackage;
+  }
+
+  @Override
+  public String getId() {
+    return id;
+  }
+
+  @Override
+  public File getFolder() {
+    return null;
+  }
+
+  @Override
+  public Map getBoards() {
+    return null;
+  }
+
+  @Override
+  public PreferencesMap getCustomMenus() {
+    return null;
+  }
+
+  @Override
+  public Set getCustomMenuIds() {
+    return null;
+  }
+
+  @Override
+  public Map getProgrammers() {
+    return null;
+  }
+
+  @Override
+  public PreferencesMap getProgrammer(String programmer) {
+    return null;
+  }
+
+  @Override
+  public PreferencesMap getTool(String tool) {
+    return null;
+  }
+
+  @Override
+  public PreferencesMap getPreferences() {
+    return null;
+  }
+
+  @Override
+  public TargetBoard getBoard(String boardId) {
+    return null;
+  }
+
+  @Override
+  public TargetPackage getContainerPackage() {
+    return targetPackage;
+  }
+}
diff --git a/app/test/processing/app/debug/UploaderFactoryTest.java b/app/test/processing/app/debug/UploaderFactoryTest.java
index 5365f97bc..827025265 100644
--- a/app/test/processing/app/debug/UploaderFactoryTest.java
+++ b/app/test/processing/app/debug/UploaderFactoryTest.java
@@ -1,3 +1,32 @@
+/*
+ * This file is part of Arduino.
+ *
+ * Copyright 2015 Arduino LLC (http://www.arduino.cc/)
+ *
+ * Arduino 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction.  Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License.  This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ */
+
 package processing.app.debug;
 
 import cc.arduino.packages.BoardPort;
@@ -5,26 +34,21 @@ import cc.arduino.packages.Uploader;
 import cc.arduino.packages.UploaderFactory;
 import cc.arduino.packages.uploaders.SSHUploader;
 import cc.arduino.packages.uploaders.SerialUploader;
-import org.junit.Before;
 import org.junit.Test;
 import processing.app.AbstractWithPreferencesTest;
+import processing.app.helpers.PreferencesMap;
 
-import java.io.File;
+import java.util.HashMap;
 
 import static org.junit.Assert.assertTrue;
 
 public class UploaderFactoryTest extends AbstractWithPreferencesTest {
 
-  private TargetPackage targetPackage;
-
-  @Before
-  public void setUp() throws Exception {
-    targetPackage = new TargetPackage("arduino", new File(".", "hardware/arduino/"));
-  }
-
   @Test
   public void shouldCreateAnInstanceOfSSHUploader() throws Exception {
-    TargetBoard board = targetPackage.getPlatforms().get("avr").getBoards().get("yun");
+    TargetBoard board = new LegacyTargetBoard("yun", new PreferencesMap(new HashMap()), new TargetPlatformStub("id", new TargetPackageStub("id")));
+    board.getPreferences().put("upload.via_ssh", "true");
+
     BoardPort boardPort = new BoardPort();
     boardPort.setBoardName("yun");
     boardPort.setAddress("192.168.0.1");
@@ -36,7 +60,9 @@ public class UploaderFactoryTest extends AbstractWithPreferencesTest {
 
   @Test
   public void shouldCreateAnInstanceOfBasicUploaderWhenSSHIsUnsupported() throws Exception {
-    TargetBoard board = targetPackage.getPlatforms().get("avr").getBoards().get("uno");
+    TargetBoard board = new LegacyTargetBoard("uno", new PreferencesMap(new HashMap()), new TargetPlatformStub("id", new TargetPackageStub("id")));
+    board.getPreferences().put("upload.via_ssh", "false");
+
     BoardPort boardPort = new BoardPort();
     boardPort.setBoardName("myyun");
     boardPort.setAddress("192.168.0.1");
@@ -48,7 +74,9 @@ public class UploaderFactoryTest extends AbstractWithPreferencesTest {
 
   @Test
   public void shouldCreateAnInstanceOfBasicUploaderWhenPortIsSerial() throws Exception {
-    TargetBoard board = targetPackage.getPlatforms().get("avr").getBoards().get("uno");
+    TargetBoard board = new LegacyTargetBoard("uno", new PreferencesMap(new HashMap()), new TargetPlatformStub("id", new TargetPackageStub("id")));
+    board.getPreferences().put("upload.via_ssh", "false");
+
     BoardPort boardPort = new BoardPort();
     boardPort.setBoardName("Arduino Leonardo");
     boardPort.setAddress("/dev/ttyACM0");
diff --git a/app/test/processing/app/helpers/ArduinoFrameFixture.java b/app/test/processing/app/helpers/ArduinoFrameFixture.java
index a5832a904..9f597e27b 100644
--- a/app/test/processing/app/helpers/ArduinoFrameFixture.java
+++ b/app/test/processing/app/helpers/ArduinoFrameFixture.java
@@ -1,8 +1,37 @@
+/*
+ * This file is part of Arduino.
+ *
+ * Copyright 2015 Arduino LLC (http://www.arduino.cc/)
+ *
+ * Arduino 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction.  Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License.  This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ */
+
 package processing.app.helpers;
 
 import org.fest.swing.fixture.FrameFixture;
 import processing.app.Editor;
-import processing.app.syntax.JEditTextArea;
+import processing.app.syntax.SketchTextArea;
 
 public class ArduinoFrameFixture extends FrameFixture {
 
@@ -13,8 +42,8 @@ public class ArduinoFrameFixture extends FrameFixture {
     this.editor = editor;
   }
 
-  public JEditTextAreaFixture jEditTextArea(String name) {
-    return new JEditTextAreaFixture(robot, (JEditTextArea) this.robot.finder().find(new JEditTextAreaComponentMatcher(name)));
+  public SketchTextAreaFixture textArea(String name) {
+    return new SketchTextAreaFixture(robot, (SketchTextArea) this.robot.finder().find(new SketchTextAreaComponentMatcher(name)));
   }
 
   public Editor getEditor() {
diff --git a/app/test/processing/app/helpers/JEditTextAreaComponentDriver.java b/app/test/processing/app/helpers/JEditTextAreaComponentDriver.java
deleted file mode 100644
index f292c3998..000000000
--- a/app/test/processing/app/helpers/JEditTextAreaComponentDriver.java
+++ /dev/null
@@ -1,79 +0,0 @@
-package processing.app.helpers;
-
-import org.fest.swing.core.Robot;
-import org.fest.swing.driver.JComponentDriver;
-import org.fest.swing.edt.GuiActionRunner;
-import org.fest.swing.edt.GuiQuery;
-import processing.app.syntax.JEditTextArea;
-
-public class JEditTextAreaComponentDriver extends JComponentDriver {
-
-  public JEditTextAreaComponentDriver(Robot robot) {
-    super(robot);
-  }
-
-  public void enterText(JEditTextArea target, String text) {
-    focusAndWaitForFocusGain(target);
-    robot.enterText(text);
-  }
-
-  public void setText(final JEditTextArea target, final String text) {
-    focusAndWaitForFocusGain(target);
-    GuiActionRunner.execute(new GuiQuery() {
-
-      protected JEditTextArea executeInEDT() {
-        target.setText(text);
-        return target;
-      }
-
-    });
-    robot.waitForIdle();
-  }
-
-  public String getText(final JEditTextArea target) {
-    focusAndWaitForFocusGain(target);
-    return GuiActionRunner.execute(new GuiQuery() {
-
-      protected String executeInEDT() {
-        return target.getText();
-      }
-
-    });
-  }
-
-  public JEditTextArea selectAll(final JEditTextArea target) {
-    return GuiActionRunner.execute(new GuiQuery() {
-
-      protected JEditTextArea executeInEDT() {
-        target.selectAll();
-        return target;
-      }
-
-    });
-  }
-
-  public Integer getCaretPosition(final JEditTextArea target) {
-    focusAndWaitForFocusGain(target);
-    return GuiActionRunner.execute(new GuiQuery() {
-
-      protected Integer executeInEDT() {
-        return target.getCaretPosition();
-      }
-
-    });
-  }
-
-  public void setCaretPosition(final JEditTextArea target, final int caretPosition) {
-    focusAndWaitForFocusGain(target);
-    GuiActionRunner.execute(new GuiQuery() {
-
-      protected JEditTextArea executeInEDT() {
-        target.setCaretPosition(caretPosition);
-        return target;
-      }
-
-    });
-    robot.waitForIdle();
-  }
-
-}
diff --git a/app/test/processing/app/helpers/JEditTextAreaComponentMatcher.java b/app/test/processing/app/helpers/JEditTextAreaComponentMatcher.java
deleted file mode 100644
index f168b92b9..000000000
--- a/app/test/processing/app/helpers/JEditTextAreaComponentMatcher.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package processing.app.helpers;
-
-import org.fest.swing.core.ComponentMatcher;
-import processing.app.syntax.JEditTextArea;
-
-import java.awt.*;
-
-public class JEditTextAreaComponentMatcher implements ComponentMatcher {
-
-  private final String name;
-
-  public JEditTextAreaComponentMatcher(String name) {
-    this.name = name;
-  }
-
-  @Override
-  public boolean matches(Component component) {
-    return component instanceof JEditTextArea && name.equals(component.getName());
-  }
-}
diff --git a/app/test/processing/app/helpers/JEditTextAreaFixture.java b/app/test/processing/app/helpers/JEditTextAreaFixture.java
deleted file mode 100644
index 19560d88b..000000000
--- a/app/test/processing/app/helpers/JEditTextAreaFixture.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package processing.app.helpers;
-
-import org.fest.swing.core.Robot;
-import org.fest.swing.fixture.ComponentFixture;
-import processing.app.syntax.JEditTextArea;
-
-public class JEditTextAreaFixture extends ComponentFixture {
-
-  private final JEditTextAreaComponentDriver driver;
-
-  public JEditTextAreaFixture(Robot robot, Class type) {
-    super(robot, type);
-    this.driver = new JEditTextAreaComponentDriver(robot);
-  }
-
-  public JEditTextAreaFixture(Robot robot, String name, Class type) {
-    super(robot, name, type);
-    this.driver = new JEditTextAreaComponentDriver(robot);
-  }
-
-  public JEditTextAreaFixture(Robot robot, JEditTextArea target) {
-    super(robot, target);
-    this.driver = new JEditTextAreaComponentDriver(robot);
-  }
-
-  public JEditTextAreaFixture enterText(String text) {
-    driver.enterText((JEditTextArea) target, text);
-    return this;
-  }
-
-  public JEditTextAreaFixture setText(String text) {
-    driver.setText((JEditTextArea) target, text);
-    return this;
-  }
-
-  public String getText() {
-    return driver.getText((JEditTextArea) target);
-  }
-
-  public JEditTextAreaFixture selectAll() {
-    driver.selectAll((JEditTextArea) target);
-    return this;
-  }
-
-  public int getCaretPosition() {
-    return driver.getCaretPosition((JEditTextArea) target);
-  }
-
-  public void setCaretPosition(int caretPosition) {
-    driver.setCaretPosition((JEditTextArea) target, caretPosition);
-  }
-}
diff --git a/app/test/processing/app/helpers/SketchTextAreaComponentDriver.java b/app/test/processing/app/helpers/SketchTextAreaComponentDriver.java
new file mode 100644
index 000000000..7d569c3bf
--- /dev/null
+++ b/app/test/processing/app/helpers/SketchTextAreaComponentDriver.java
@@ -0,0 +1,109 @@
+/*
+ * This file is part of Arduino.
+ *
+ * Copyright 2015 Ricardo JL Rufino (ricardo@criativasoft.com.br)
+ * Copyright 2015 Arduino LLC
+ *
+ * Arduino 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction.  Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License.  This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ */
+
+package processing.app.helpers;
+
+import org.fest.swing.core.Robot;
+import org.fest.swing.driver.JComponentDriver;
+import org.fest.swing.edt.GuiActionRunner;
+import org.fest.swing.edt.GuiQuery;
+import processing.app.syntax.SketchTextArea;
+
+public class SketchTextAreaComponentDriver extends JComponentDriver {
+
+  public SketchTextAreaComponentDriver(Robot robot) {
+    super(robot);
+  }
+
+  public void enterText(SketchTextArea target, String text) {
+    focusAndWaitForFocusGain(target);
+    robot.enterText(text);
+  }
+
+  public void setText(final SketchTextArea target, final String text) {
+    focusAndWaitForFocusGain(target);
+    GuiActionRunner.execute(new GuiQuery() {
+
+      protected SketchTextArea executeInEDT() {
+        target.setText(text);
+        return target;
+      }
+
+    });
+    robot.waitForIdle();
+  }
+
+  public String getText(final SketchTextArea target) {
+    focusAndWaitForFocusGain(target);
+    return GuiActionRunner.execute(new GuiQuery() {
+
+      protected String executeInEDT() {
+        return target.getText();
+      }
+
+    });
+  }
+
+  public SketchTextArea selectAll(final SketchTextArea target) {
+    return GuiActionRunner.execute(new GuiQuery() {
+
+      protected SketchTextArea executeInEDT() {
+        target.selectAll();
+        return target;
+      }
+
+    });
+  }
+
+  public Integer getCaretPosition(final SketchTextArea target) {
+    focusAndWaitForFocusGain(target);
+    return GuiActionRunner.execute(new GuiQuery() {
+
+      protected Integer executeInEDT() {
+        return target.getCaretPosition();
+      }
+
+    });
+  }
+
+  public void setCaretPosition(final SketchTextArea target, final int caretPosition) {
+    focusAndWaitForFocusGain(target);
+    GuiActionRunner.execute(new GuiQuery() {
+
+      protected SketchTextArea executeInEDT() {
+        target.setCaretPosition(caretPosition);
+        return target;
+      }
+
+    });
+    robot.waitForIdle();
+  }
+
+}
diff --git a/app/test/processing/app/helpers/SketchTextAreaComponentMatcher.java b/app/test/processing/app/helpers/SketchTextAreaComponentMatcher.java
new file mode 100644
index 000000000..006ec2a91
--- /dev/null
+++ b/app/test/processing/app/helpers/SketchTextAreaComponentMatcher.java
@@ -0,0 +1,50 @@
+/*
+ * This file is part of Arduino.
+ *
+ * Copyright 2015 Ricardo JL Rufino (ricardo@criativasoft.com.br)
+ * Copyright 2015 Arduino LLC
+ *
+ * Arduino 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction.  Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License.  This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ */
+
+package processing.app.helpers;
+
+import org.fest.swing.core.ComponentMatcher;
+import processing.app.syntax.SketchTextArea;
+
+import java.awt.*;
+
+public class SketchTextAreaComponentMatcher implements ComponentMatcher {
+
+  private final String name;
+
+  public SketchTextAreaComponentMatcher(String name) {
+    this.name = name;
+  }
+
+  @Override
+  public boolean matches(Component component) {
+    return component instanceof SketchTextArea && name.equals(component.getName());
+  }
+}
diff --git a/app/test/processing/app/helpers/SketchTextAreaFixture.java b/app/test/processing/app/helpers/SketchTextAreaFixture.java
new file mode 100644
index 000000000..e5e1f703b
--- /dev/null
+++ b/app/test/processing/app/helpers/SketchTextAreaFixture.java
@@ -0,0 +1,82 @@
+/*
+ * This file is part of Arduino.
+ *
+ * Copyright 2015 Ricardo JL Rufino (ricardo@criativasoft.com.br)
+ * Copyright 2015 Arduino LLC
+ *
+ * Arduino 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction.  Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License.  This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ */
+
+package processing.app.helpers;
+
+import org.fest.swing.core.Robot;
+import org.fest.swing.fixture.ComponentFixture;
+import processing.app.syntax.SketchTextArea;
+
+public class SketchTextAreaFixture extends ComponentFixture {
+
+  private final SketchTextAreaComponentDriver driver;
+
+  public SketchTextAreaFixture(Robot robot, Class type) {
+    super(robot, type);
+    this.driver = new SketchTextAreaComponentDriver(robot);
+  }
+
+  public SketchTextAreaFixture(Robot robot, String name, Class type) {
+    super(robot, name, type);
+    this.driver = new SketchTextAreaComponentDriver(robot);
+  }
+
+  public SketchTextAreaFixture(Robot robot, SketchTextArea target) {
+    super(robot, target);
+    this.driver = new SketchTextAreaComponentDriver(robot);
+  }
+
+  public SketchTextAreaFixture enterText(String text) {
+    driver.enterText((SketchTextArea) target, text);
+    return this;
+  }
+
+  public SketchTextAreaFixture setText(String text) {
+    driver.setText((SketchTextArea) target, text);
+    return this;
+  }
+
+  public String getText() {
+    return driver.getText((SketchTextArea) target);
+  }
+
+  public SketchTextAreaFixture selectAll() {
+    driver.selectAll((SketchTextArea) target);
+    return this;
+  }
+
+  public int getCaretPosition() {
+    return driver.getCaretPosition((SketchTextArea) target);
+  }
+
+  public void setCaretPosition(int caretPosition) {
+    driver.setCaretPosition((SketchTextArea) target, caretPosition);
+  }
+}
diff --git a/app/test/processing/app/helpers/StringReplacerTest.java b/app/test/processing/app/helpers/StringReplacerTest.java
index 90ecd0144..18b7fc683 100644
--- a/app/test/processing/app/helpers/StringReplacerTest.java
+++ b/app/test/processing/app/helpers/StringReplacerTest.java
@@ -1,3 +1,32 @@
+/*
+ * This file is part of Arduino.
+ *
+ * Copyright 2015 Arduino LLC (http://www.arduino.cc/)
+ *
+ * Arduino 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction.  Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License.  This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ */
+
 package processing.app.helpers;
 
 import static org.junit.Assert.assertArrayEquals;
diff --git a/app/test/processing/app/linux/UDevAdmParserTest.java b/app/test/processing/app/linux/UDevAdmParserTest.java
index efcc70bfb..a7a2b6c59 100644
--- a/app/test/processing/app/linux/UDevAdmParserTest.java
+++ b/app/test/processing/app/linux/UDevAdmParserTest.java
@@ -1,3 +1,32 @@
+/*
+ * This file is part of Arduino.
+ *
+ * Copyright 2015 Arduino LLC (http://www.arduino.cc/)
+ *
+ * Arduino 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction.  Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License.  This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ */
+
 package processing.app.linux;
 
 import org.junit.Test;
diff --git a/app/test/processing/app/macosx/SystemProfilerParserTest.java b/app/test/processing/app/macosx/SystemProfilerParserTest.java
index 3f2e0b9de..30c6f6b63 100644
--- a/app/test/processing/app/macosx/SystemProfilerParserTest.java
+++ b/app/test/processing/app/macosx/SystemProfilerParserTest.java
@@ -1,3 +1,32 @@
+/*
+ * This file is part of Arduino.
+ *
+ * Copyright 2015 Arduino LLC (http://www.arduino.cc/)
+ *
+ * Arduino 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction.  Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License.  This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ */
+
 package processing.app.macosx;
 
 import org.junit.Test;
diff --git a/app/test/processing/app/preproc/PdePreprocessorTest.java b/app/test/processing/app/preproc/PdePreprocessorTest.java
index aa66a84b6..ef2f916c1 100644
--- a/app/test/processing/app/preproc/PdePreprocessorTest.java
+++ b/app/test/processing/app/preproc/PdePreprocessorTest.java
@@ -1,3 +1,32 @@
+/*
+ * This file is part of Arduino.
+ *
+ * Copyright 2015 Arduino LLC (http://www.arduino.cc/)
+ *
+ * Arduino 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction.  Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License.  This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ */
+
 package processing.app.preproc;
 
 import org.junit.Test;
diff --git a/app/test/processing/app/syntax/PdeKeywordsTest.java b/app/test/processing/app/syntax/PdeKeywordsTest.java
new file mode 100644
index 000000000..29c6b4675
--- /dev/null
+++ b/app/test/processing/app/syntax/PdeKeywordsTest.java
@@ -0,0 +1,59 @@
+/*
+ * This file is part of Arduino.
+ *
+ * Copyright 2015 Arduino LLC
+ *
+ * Arduino 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction.  Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License.  This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ */
+
+package processing.app.syntax;
+
+import org.fife.ui.rsyntaxtextarea.TokenTypes;
+import org.junit.Test;
+import processing.app.AbstractWithPreferencesTest;
+import processing.app.BaseNoGui;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+public class PdeKeywordsTest extends AbstractWithPreferencesTest {
+
+  @Test
+  public void testKeywordsTxtParsing() throws Exception {
+    PdeKeywords pdeKeywords = new PdeKeywords();
+    pdeKeywords.reload();
+
+    assertEquals("Constants", pdeKeywords.getReference("HIGH"));
+    assertEquals("RESERVED_WORD_2", pdeKeywords.getTokenTypeAsString("HIGH"));
+    assertEquals(TokenTypes.RESERVED_WORD_2, pdeKeywords.getTokenType("HIGH".toCharArray(), 0, 3));
+
+    assertEquals("IncrementCompound", pdeKeywords.getReference("+="));
+    assertNull(pdeKeywords.getTokenTypeAsString("+="));
+
+    assertNull(pdeKeywords.getReference("Mouse"));
+    assertEquals("DATA_TYPE", pdeKeywords.getTokenTypeAsString("Mouse"));
+    assertEquals(TokenTypes.DATA_TYPE, pdeKeywords.getTokenType("Mouse".toCharArray(), 0, 4));
+  }
+
+}
diff --git a/app/test/processing/app/tools/ZipDeflaterTest.java b/app/test/processing/app/tools/ZipDeflaterTest.java
index ba240254d..21f28cc29 100644
--- a/app/test/processing/app/tools/ZipDeflaterTest.java
+++ b/app/test/processing/app/tools/ZipDeflaterTest.java
@@ -1,3 +1,32 @@
+/*
+ * This file is part of Arduino.
+ *
+ * Copyright 2015 Arduino LLC (http://www.arduino.cc/)
+ *
+ * Arduino 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction.  Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License.  This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ */
+
 package processing.app.tools;
 
 import static org.junit.Assert.assertEquals;
diff --git a/app/test/processing/app/windows/ListComPortsParserTest.java b/app/test/processing/app/windows/ListComPortsParserTest.java
index dd6d9755a..e75857933 100644
--- a/app/test/processing/app/windows/ListComPortsParserTest.java
+++ b/app/test/processing/app/windows/ListComPortsParserTest.java
@@ -1,3 +1,32 @@
+/*
+ * This file is part of Arduino.
+ *
+ * Copyright 2015 Arduino LLC (http://www.arduino.cc/)
+ *
+ * Arduino 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction.  Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License.  This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ */
+
 package processing.app.windows;
 
 import org.junit.Test;
@@ -14,5 +43,15 @@ public class ListComPortsParserTest {
     assertEquals("0X16C0_0X0483", new ListComPortsParser().extractVIDAndPID(listComPortsOutput, "COM24"));
   }
 
+  @Test
+  public void shouldFindVIDPID2() throws Exception {
+    String listComPortsOutput = "COM1 - (Standard port types) - ACPI\\PNP0501\\1\n" +
+            "COM3 - IVT Corporation - {F12D3CF8-B11D-457E-8641-BE2AF2D6D204}\\IVTCOMM\\1&27902E60&2&0001\n" +
+            "COM4 - IVT Corporation - {F12D3CF8-B11D-457E-8641-BE2AF2D6D204}\\IVTCOMM\\1&27902E60&2&0002\n" +
+            "COM18 - FTDI - FTDIBUS\\VID_0403+PID_0000+A9EPHBR7A\\0000";
+
+    assertEquals("0X0403_0X0000", new ListComPortsParser().extractVIDAndPID(listComPortsOutput, "COM18"));
+  }
+
 
 }
diff --git a/arduino-core/.classpath b/arduino-core/.classpath
index bf61b5826..cd3604c15 100644
--- a/arduino-core/.classpath
+++ b/arduino-core/.classpath
@@ -9,5 +9,26 @@
 	
 	
 	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
 	
 
diff --git a/arduino-core/.editorconfig b/arduino-core/.editorconfig
new file mode 100644
index 000000000..bd8c8987e
--- /dev/null
+++ b/arduino-core/.editorconfig
@@ -0,0 +1,16 @@
+# EditorConfig is awesome: http://EditorConfig.org
+
+# top-most EditorConfig file
+root = true
+
+# Unix-style newlines with a newline ending every file
+[*]
+end_of_line = lf
+insert_final_newline = true
+indent_style = space
+indent_size = 2
+charset = utf-8
+
+[*.{md,adoc}]
+indent_style = space
+trim_trailing_whitespace = false
diff --git a/arduino-core/lib/bcpg-jdk15on-152.jar b/arduino-core/lib/bcpg-jdk15on-152.jar
new file mode 100644
index 000000000..4f5c63105
Binary files /dev/null and b/arduino-core/lib/bcpg-jdk15on-152.jar differ
diff --git a/arduino-core/lib/bcprov-jdk15on-152.jar b/arduino-core/lib/bcprov-jdk15on-152.jar
new file mode 100644
index 000000000..6c54dd901
Binary files /dev/null and b/arduino-core/lib/bcprov-jdk15on-152.jar differ
diff --git a/arduino-core/lib/commons-codec-1.7.jar b/arduino-core/lib/commons-codec-1.7.jar
new file mode 100644
index 000000000..efa7f7291
Binary files /dev/null and b/arduino-core/lib/commons-codec-1.7.jar differ
diff --git a/arduino-core/lib/commons-compress-1.8.jar b/arduino-core/lib/commons-compress-1.8.jar
new file mode 100644
index 000000000..940b06873
Binary files /dev/null and b/arduino-core/lib/commons-compress-1.8.jar differ
diff --git a/arduino-core/lib/commons-compress.LICENSE.ASL-2.0.txt b/arduino-core/lib/commons-compress.LICENSE.ASL-2.0.txt
new file mode 100644
index 000000000..d64569567
--- /dev/null
+++ b/arduino-core/lib/commons-compress.LICENSE.ASL-2.0.txt
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/arduino-core/lib/commons-lang3-3.3.2.jar b/arduino-core/lib/commons-lang3-3.3.2.jar
new file mode 100644
index 000000000..2ce08ae99
Binary files /dev/null and b/arduino-core/lib/commons-lang3-3.3.2.jar differ
diff --git a/arduino-core/lib/commons-lang3.LICENSE.ASL-2.0.txt b/arduino-core/lib/commons-lang3.LICENSE.ASL-2.0.txt
new file mode 100644
index 000000000..d64569567
--- /dev/null
+++ b/arduino-core/lib/commons-lang3.LICENSE.ASL-2.0.txt
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/arduino-core/lib/guava-18.0.LICENSE.ASL-2.0.txt b/arduino-core/lib/guava-18.0.LICENSE.ASL-2.0.txt
new file mode 100644
index 000000000..6b0b1270f
--- /dev/null
+++ b/arduino-core/lib/guava-18.0.LICENSE.ASL-2.0.txt
@@ -0,0 +1,203 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
diff --git a/arduino-core/lib/guava-18.0.jar b/arduino-core/lib/guava-18.0.jar
new file mode 100644
index 000000000..8f89e4901
Binary files /dev/null and b/arduino-core/lib/guava-18.0.jar differ
diff --git a/arduino-core/lib/jackson-annotations-2.2.3.jar b/arduino-core/lib/jackson-annotations-2.2.3.jar
new file mode 100644
index 000000000..b62c87d7e
Binary files /dev/null and b/arduino-core/lib/jackson-annotations-2.2.3.jar differ
diff --git a/arduino-core/lib/jackson-core-2.2.3.jar b/arduino-core/lib/jackson-core-2.2.3.jar
new file mode 100644
index 000000000..24318a464
Binary files /dev/null and b/arduino-core/lib/jackson-core-2.2.3.jar differ
diff --git a/arduino-core/lib/jackson-databind-2.2.3.jar b/arduino-core/lib/jackson-databind-2.2.3.jar
new file mode 100644
index 000000000..854508478
Binary files /dev/null and b/arduino-core/lib/jackson-databind-2.2.3.jar differ
diff --git a/arduino-core/lib/jackson-module-mrbean-2.2.3.jar b/arduino-core/lib/jackson-module-mrbean-2.2.3.jar
new file mode 100644
index 000000000..a4a3b738e
Binary files /dev/null and b/arduino-core/lib/jackson-module-mrbean-2.2.3.jar differ
diff --git a/arduino-core/lib/java-semver-0.8.0.jar b/arduino-core/lib/java-semver-0.8.0.jar
new file mode 100644
index 000000000..967f0d154
Binary files /dev/null and b/arduino-core/lib/java-semver-0.8.0.jar differ
diff --git a/arduino-core/lib/java-semver.LICENSE.MIT.txt b/arduino-core/lib/java-semver.LICENSE.MIT.txt
new file mode 100644
index 000000000..e69de29bb
diff --git a/arduino-core/src/cc/arduino/DefaultUncaughtExceptionHandler.java b/arduino-core/src/cc/arduino/DefaultUncaughtExceptionHandler.java
new file mode 100644
index 000000000..3b7a2a37e
--- /dev/null
+++ b/arduino-core/src/cc/arduino/DefaultUncaughtExceptionHandler.java
@@ -0,0 +1,40 @@
+/*
+ * This file is part of Arduino.
+ *
+ * Copyright 2015 Arduino LLC (http://www.arduino.cc/)
+ *
+ * Arduino 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction.  Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License.  This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ */
+
+package cc.arduino;
+
+public class DefaultUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
+
+  @Override
+  public void uncaughtException(Thread t, Throwable e) {
+    System.err.println(t);
+    e.printStackTrace();
+  }
+
+}
diff --git a/arduino-core/src/cc/arduino/contributions/DownloadableContributionBuiltInAtTheBottomComparator.java b/arduino-core/src/cc/arduino/contributions/DownloadableContributionBuiltInAtTheBottomComparator.java
new file mode 100644
index 000000000..cb27b6bfa
--- /dev/null
+++ b/arduino-core/src/cc/arduino/contributions/DownloadableContributionBuiltInAtTheBottomComparator.java
@@ -0,0 +1,45 @@
+/*
+ * This file is part of Arduino.
+ *
+ * Copyright 2015 Arduino LLC (http://www.arduino.cc/)
+ *
+ * Arduino 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction.  Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License.  This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ */
+
+package cc.arduino.contributions;
+
+import cc.arduino.contributions.packages.DownloadableContribution;
+
+import java.util.Comparator;
+
+public class DownloadableContributionBuiltInAtTheBottomComparator implements Comparator {
+  @Override
+  public int compare(DownloadableContribution p1, DownloadableContribution p2) {
+    if (p1.isReadOnly() == p2.isReadOnly()) {
+      return 0;
+    }
+
+    return p1.isReadOnly() ? 1 : -1;
+  }
+}
diff --git a/arduino-core/src/cc/arduino/contributions/DownloadableContributionVersionComparator.java b/arduino-core/src/cc/arduino/contributions/DownloadableContributionVersionComparator.java
new file mode 100644
index 000000000..f23fa552d
--- /dev/null
+++ b/arduino-core/src/cc/arduino/contributions/DownloadableContributionVersionComparator.java
@@ -0,0 +1,50 @@
+/*
+ * This file is part of Arduino.
+ *
+ * Copyright 2015 Arduino LLC (http://www.arduino.cc/)
+ *
+ * Arduino 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction.  Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License.  This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ */
+
+package cc.arduino.contributions;
+
+import cc.arduino.contributions.packages.DownloadableContribution;
+
+import java.util.Comparator;
+
+public class DownloadableContributionVersionComparator implements Comparator {
+
+  private final VersionComparator versionComparator;
+
+  public DownloadableContributionVersionComparator() {
+    versionComparator = new VersionComparator();
+  }
+
+  @Override
+  public int compare(DownloadableContribution lib1, DownloadableContribution lib2) {
+    return versionComparator.compare(lib1.getParsedVersion(), lib2.getParsedVersion());
+  }
+
+
+}
diff --git a/arduino-core/src/cc/arduino/contributions/GPGDetachedSignatureVerifier.java b/arduino-core/src/cc/arduino/contributions/GPGDetachedSignatureVerifier.java
new file mode 100644
index 000000000..2b23c3387
--- /dev/null
+++ b/arduino-core/src/cc/arduino/contributions/GPGDetachedSignatureVerifier.java
@@ -0,0 +1,121 @@
+/*
+ * This file is part of Arduino.
+ *
+ * Arduino 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction.  Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License.  This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ *
+ * Copyright 2015 Arduino LLC (http://www.arduino.cc/)
+ */
+
+package cc.arduino.contributions;
+
+import org.apache.commons.compress.utils.IOUtils;
+import org.bouncycastle.openpgp.*;
+import org.bouncycastle.openpgp.operator.bc.BcKeyFingerprintCalculator;
+import org.bouncycastle.openpgp.operator.bc.BcPGPContentVerifierBuilderProvider;
+
+import java.io.*;
+import java.util.Iterator;
+
+public class GPGDetachedSignatureVerifier {
+
+  private String keyId;
+
+  public GPGDetachedSignatureVerifier() {
+    this("7F294291");
+  }
+
+  public GPGDetachedSignatureVerifier(String keyId) {
+    this.keyId = keyId;
+  }
+
+  public boolean verify(File signedFile, File signature, File publicKey) throws IOException, PGPException {
+    PGPPublicKey pgpPublicKey = readPublicKey(publicKey, keyId);
+
+    FileInputStream signatureInputStream = null;
+    FileInputStream signedFileInputStream = null;
+    try {
+      signatureInputStream = new FileInputStream(signature);
+      PGPObjectFactory pgpObjectFactory = new PGPObjectFactory(signatureInputStream, new BcKeyFingerprintCalculator());
+
+      Object nextObject;
+      try {
+        nextObject = pgpObjectFactory.nextObject();
+        if (!(nextObject instanceof PGPSignatureList)) {
+          return false;
+        }
+      } catch (IOException e) {
+        return false;
+      }
+      PGPSignatureList pgpSignatureList = (PGPSignatureList) nextObject;
+      assert pgpSignatureList.size() == 1;
+      PGPSignature pgpSignature = pgpSignatureList.get(0);
+
+      pgpSignature.init(new BcPGPContentVerifierBuilderProvider(), pgpPublicKey);
+      signedFileInputStream = new FileInputStream(signedFile);
+      pgpSignature.update(IOUtils.toByteArray(signedFileInputStream));
+
+      return pgpSignature.verify();
+    } finally {
+      if (signatureInputStream != null) {
+        signatureInputStream.close();
+      }
+      if (signedFileInputStream != null) {
+        signedFileInputStream.close();
+      }
+    }
+  }
+
+  private PGPPublicKey readPublicKey(File file, String keyId) throws IOException, PGPException {
+    InputStream keyIn = null;
+    try {
+      keyIn = new BufferedInputStream(new FileInputStream(file));
+      return readPublicKey(keyIn, keyId);
+    } finally {
+      if (keyIn != null) {
+        keyIn.close();
+      }
+    }
+  }
+
+  private PGPPublicKey readPublicKey(InputStream input, String keyId) throws IOException, PGPException {
+    PGPPublicKeyRingCollection pgpPub = new PGPPublicKeyRingCollection(PGPUtil.getDecoderStream(input), new BcKeyFingerprintCalculator());
+
+    Iterator keyRingIter = pgpPub.getKeyRings();
+    while (keyRingIter.hasNext()) {
+      PGPPublicKeyRing keyRing = (PGPPublicKeyRing) keyRingIter.next();
+
+      Iterator keyIter = keyRing.getPublicKeys();
+      while (keyIter.hasNext()) {
+        PGPPublicKey key = (PGPPublicKey) keyIter.next();
+
+        if (Long.toHexString(key.getKeyID()).toUpperCase().endsWith(keyId)) {
+          return key;
+        }
+      }
+    }
+
+    throw new IllegalArgumentException("Can't find encryption key in key ring.");
+  }
+
+}
diff --git a/arduino-core/src/cc/arduino/contributions/SignatureVerificationFailedException.java b/arduino-core/src/cc/arduino/contributions/SignatureVerificationFailedException.java
new file mode 100644
index 000000000..201e7ec45
--- /dev/null
+++ b/arduino-core/src/cc/arduino/contributions/SignatureVerificationFailedException.java
@@ -0,0 +1,16 @@
+package cc.arduino.contributions;
+
+import processing.app.I18n;
+
+import static processing.app.I18n._;
+
+public class SignatureVerificationFailedException extends Exception {
+
+  public SignatureVerificationFailedException(String filename) {
+    super(I18n.format(_("{0} file signature verification failed"), filename));
+  }
+
+  public SignatureVerificationFailedException(String filename, Throwable cause) {
+    super(I18n.format(_("{0} file signature verification failed"), filename), cause);
+  }
+}
diff --git a/arduino-core/src/cc/arduino/contributions/VersionComparator.java b/arduino-core/src/cc/arduino/contributions/VersionComparator.java
new file mode 100644
index 000000000..d4bd52a85
--- /dev/null
+++ b/arduino-core/src/cc/arduino/contributions/VersionComparator.java
@@ -0,0 +1,71 @@
+/*
+ * This file is part of Arduino.
+ *
+ * Copyright 2014 Arduino LLC (http://www.arduino.cc/)
+ *
+ * Arduino 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction.  Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License.  This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ */
+package cc.arduino.contributions;
+
+import com.github.zafarkhaja.semver.Version;
+
+import java.util.Comparator;
+
+public class VersionComparator implements Comparator {
+
+  @Override
+  public int compare(String a, String b) {
+    // null is always less than any other value
+    if (a == null && b == null)
+      return 0;
+    if (a == null)
+      return -1;
+    if (b == null)
+      return 1;
+
+    Version versionA = VersionHelper.valueOf(a);
+    Version versionB = VersionHelper.valueOf(b);
+
+    return versionA.compareTo(versionB);
+  }
+
+  public boolean greaterThan(String a, String b) {
+    // null is always less than any other value
+    if (a == null && b == null) {
+      return false;
+    }
+    if (a == null) {
+      return false;
+    }
+    if (b == null) {
+      return true;
+    }
+
+    Version versionA = VersionHelper.valueOf(a);
+    Version versionB = VersionHelper.valueOf(b);
+
+    return versionA.greaterThan(versionB);
+  }
+
+}
diff --git a/arduino-core/src/cc/arduino/contributions/VersionHelper.java b/arduino-core/src/cc/arduino/contributions/VersionHelper.java
new file mode 100644
index 000000000..fee87f87c
--- /dev/null
+++ b/arduino-core/src/cc/arduino/contributions/VersionHelper.java
@@ -0,0 +1,57 @@
+/*
+ * This file is part of Arduino.
+ *
+ * Copyright 2015 Arduino LLC (http://www.arduino.cc/)
+ *
+ * Arduino 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction.  Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License.  This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ */
+
+package cc.arduino.contributions;
+
+import com.github.zafarkhaja.semver.Version;
+
+public class VersionHelper {
+
+  public static Version valueOf(String ver) {
+    if (ver == null) {
+      return null;
+    }
+    try {
+      String[] verParts = ver.split("\\.");
+      if (verParts.length < 3) {
+        if (verParts.length == 2) {
+          return Version.forIntegers(Integer.valueOf(verParts[0]), Integer.valueOf(verParts[1]));
+        } else {
+          return Version.forIntegers(Integer.valueOf(verParts[0]));
+        }
+      } else {
+        return Version.valueOf(ver);
+      }
+    } catch (Exception e) {
+      System.err.println("Invalid version found: " + ver);
+      return null;
+    }
+  }
+
+}
diff --git a/arduino-core/src/cc/arduino/contributions/filters/BuiltInPredicate.java b/arduino-core/src/cc/arduino/contributions/filters/BuiltInPredicate.java
new file mode 100644
index 000000000..3b6f40a02
--- /dev/null
+++ b/arduino-core/src/cc/arduino/contributions/filters/BuiltInPredicate.java
@@ -0,0 +1,46 @@
+/*
+ * This file is part of Arduino.
+ *
+ * Copyright 2015 Arduino LLC (http://www.arduino.cc/)
+ *
+ * Arduino 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction.  Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License.  This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ */
+
+package cc.arduino.contributions.filters;
+
+import cc.arduino.contributions.packages.DownloadableContribution;
+import com.google.common.base.Predicate;
+
+public class BuiltInPredicate implements Predicate {
+
+  @Override
+  public boolean apply(DownloadableContribution input) {
+    return input.isReadOnly();
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    return obj instanceof BuiltInPredicate;
+  }
+}
diff --git a/arduino-core/src/cc/arduino/contributions/filters/DownloadableContributionWithVersionPredicate.java b/arduino-core/src/cc/arduino/contributions/filters/DownloadableContributionWithVersionPredicate.java
new file mode 100644
index 000000000..b2954fae3
--- /dev/null
+++ b/arduino-core/src/cc/arduino/contributions/filters/DownloadableContributionWithVersionPredicate.java
@@ -0,0 +1,47 @@
+/*
+ * This file is part of Arduino.
+ *
+ * Copyright 2015 Arduino LLC (http://www.arduino.cc/)
+ *
+ * Arduino 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction.  Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License.  This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ */
+
+package cc.arduino.contributions.filters;
+
+import cc.arduino.contributions.packages.DownloadableContribution;
+import com.google.common.base.Predicate;
+
+public class DownloadableContributionWithVersionPredicate implements Predicate {
+  private final String version;
+
+  public DownloadableContributionWithVersionPredicate(String version) {
+    this.version = version;
+  }
+
+  @Override
+  public boolean apply(DownloadableContribution contribution) {
+    return version.equals(contribution.getParsedVersion());
+  }
+
+}
diff --git a/arduino-core/src/cc/arduino/contributions/filters/InstalledPredicate.java b/arduino-core/src/cc/arduino/contributions/filters/InstalledPredicate.java
new file mode 100644
index 000000000..9ffc43234
--- /dev/null
+++ b/arduino-core/src/cc/arduino/contributions/filters/InstalledPredicate.java
@@ -0,0 +1,46 @@
+/*
+ * This file is part of Arduino.
+ *
+ * Copyright 2015 Arduino LLC (http://www.arduino.cc/)
+ *
+ * Arduino 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction.  Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License.  This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ */
+
+package cc.arduino.contributions.filters;
+
+import cc.arduino.contributions.packages.DownloadableContribution;
+import com.google.common.base.Predicate;
+
+public class InstalledPredicate implements Predicate {
+  @Override
+  public boolean apply(DownloadableContribution input) {
+    return input.isInstalled();
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    return obj instanceof DownloadableContribution;
+  }
+
+}
diff --git a/arduino-core/src/cc/arduino/contributions/libraries/ContributedLibrary.java b/arduino-core/src/cc/arduino/contributions/libraries/ContributedLibrary.java
new file mode 100644
index 000000000..c368f7319
--- /dev/null
+++ b/arduino-core/src/cc/arduino/contributions/libraries/ContributedLibrary.java
@@ -0,0 +1,153 @@
+/*
+ * This file is part of Arduino.
+ *
+ * Copyright 2014 Arduino LLC (http://www.arduino.cc/)
+ *
+ * Arduino 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction.  Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License.  This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ */
+package cc.arduino.contributions.libraries;
+
+import cc.arduino.contributions.packages.DownloadableContribution;
+import processing.app.I18n;
+
+import java.util.Comparator;
+import java.util.List;
+
+import static processing.app.I18n._;
+
+public abstract class ContributedLibrary extends DownloadableContribution {
+
+  public abstract String getName();
+
+  public abstract String getMaintainer();
+
+  public abstract String getAuthor();
+
+  public abstract String getWebsite();
+
+  public abstract String getCategory();
+
+  public abstract void setCategory(String category);
+
+  public abstract String getLicense();
+
+  public abstract String getParagraph();
+
+  public abstract String getSentence();
+
+  public abstract List getArchitectures();
+
+  public abstract List getTypes();
+
+  public abstract List getRequires();
+
+  public static final Comparator CASE_INSENSITIVE_ORDER = new Comparator() {
+    @Override
+    public int compare(ContributedLibrary o1, ContributedLibrary o2) {
+      return o1.getName().compareToIgnoreCase(o2.getName());
+    }
+  };
+
+  /**
+   * Returns true if the library declares to support the specified
+   * architecture (through the "architectures" property field).
+   *
+   * @param reqArch
+   * @return
+   */
+  public boolean supportsArchitecture(String reqArch) {
+    return getArchitectures().contains(reqArch) || getArchitectures().contains("*");
+  }
+
+  /**
+   * Returns true if the library declares to support at least one of the
+   * specified architectures.
+   *
+   * @param reqArchs A List of architectures to check
+   * @return
+   */
+  public boolean supportsArchitecture(List reqArchs) {
+    if (reqArchs.contains("*"))
+      return true;
+    for (String reqArch : reqArchs)
+      if (supportsArchitecture(reqArch))
+        return true;
+    return false;
+  }
+
+  @Override
+  public String toString() {
+    return I18n.format(_("Version {0}"), getParsedVersion());
+  }
+
+  public String info() {
+    String res = "";
+    res += "  ContributedLibrary : " + getName() + "\n";
+    res += "              author : " + getAuthor() + "\n";
+    res += "          maintainer : " + getMaintainer() + "\n";
+    res += "             version : " + getParsedVersion() + "\n";
+    res += "             website : " + getUrl() + "\n";
+    res += "            category : " + getCategory() + "\n";
+    res += "             license : " + getLicense() + "\n";
+    res += "             descrip : " + getSentence() + "\n";
+    if (getParagraph() != null && !getParagraph().isEmpty())
+      res += "                       " + getParagraph() + "\n";
+    res += "       architectures : ";
+    if (getArchitectures() != null)
+      for (String a : getArchitectures()) {
+        res += a + ",";
+      }
+    res += "\n";
+    res += "            requires :\n";
+    if (getRequires() != null)
+      for (ContributedLibraryReference r : getRequires()) {
+        res += "                       " + r;
+      }
+    res += "\n";
+
+    // DownloadableContribution
+    res += super.toString();
+
+    return res;
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    if (!(obj instanceof ContributedLibrary)) {
+      return false;
+    }
+
+    String thisVersion = getParsedVersion();
+    String otherVersion = ((ContributedLibrary) obj).getParsedVersion();
+
+    boolean versionEquals = thisVersion == otherVersion || (thisVersion != null && otherVersion != null && thisVersion.equals(otherVersion));
+
+    String thisName = getName();
+    String otherName = ((ContributedLibrary) obj).getName();
+
+    boolean nameEquals = thisName == null || otherName == null || thisName.equals(otherName);
+
+    return versionEquals && nameEquals;
+  }
+}
diff --git a/arduino-core/src/cc/arduino/contributions/libraries/ContributedLibraryReference.java b/arduino-core/src/cc/arduino/contributions/libraries/ContributedLibraryReference.java
new file mode 100644
index 000000000..e04a7ec7a
--- /dev/null
+++ b/arduino-core/src/cc/arduino/contributions/libraries/ContributedLibraryReference.java
@@ -0,0 +1,43 @@
+/*
+ * This file is part of Arduino.
+ *
+ * Copyright 2014 Arduino LLC (http://www.arduino.cc/)
+ *
+ * Arduino 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction.  Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License.  This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ */
+package cc.arduino.contributions.libraries;
+
+public abstract class ContributedLibraryReference {
+
+  public abstract String getName();
+
+  public abstract String getMaintainer();
+
+  public abstract String getVersion();
+
+  @Override
+  public String toString() {
+    return getName() + " " + getVersion() + " (" + getMaintainer() + ")";
+  }
+}
diff --git a/arduino-core/src/cc/arduino/contributions/libraries/LibrariesIndex.java b/arduino-core/src/cc/arduino/contributions/libraries/LibrariesIndex.java
new file mode 100644
index 000000000..cb91caf35
--- /dev/null
+++ b/arduino-core/src/cc/arduino/contributions/libraries/LibrariesIndex.java
@@ -0,0 +1,104 @@
+/*
+ * This file is part of Arduino.
+ *
+ * Copyright 2014 Arduino LLC (http://www.arduino.cc/)
+ *
+ * Arduino 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction.  Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License.  This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ */
+
+package cc.arduino.contributions.libraries;
+
+import cc.arduino.contributions.DownloadableContributionBuiltInAtTheBottomComparator;
+import cc.arduino.contributions.filters.InstalledPredicate;
+import cc.arduino.contributions.libraries.filters.LibraryWithNamePredicate;
+import com.google.common.collect.Collections2;
+
+import java.util.*;
+
+public abstract class LibrariesIndex {
+
+  public abstract List getLibraries();
+
+  public List find(final String name) {
+    return new LinkedList(Collections2.filter(getLibraries(), new LibraryWithNamePredicate(name)));
+  }
+
+  public ContributedLibrary find(String name, String version) {
+    if (name == null || version == null) {
+      return null;
+    }
+    for (ContributedLibrary lib : find(name)) {
+      if (version.equals(lib.getParsedVersion())) {
+        return lib;
+      }
+    }
+    return null;
+  }
+
+  @Override
+  public String toString() {
+    StringBuilder sb = new StringBuilder();
+    for (ContributedLibrary library : getLibraries()) {
+      sb.append(library.toString());
+    }
+    return sb.toString();
+  }
+
+  public List getCategories() {
+    List categories = new LinkedList();
+    for (ContributedLibrary lib : getLibraries()) {
+      if (lib.getCategory() != null && !categories.contains(lib.getCategory())) {
+        categories.add(lib.getCategory());
+      }
+    }
+    Collections.sort(categories);
+
+    return categories;
+  }
+
+  public List getTypes() {
+    Collection typesAccumulator = new HashSet();
+    for (ContributedLibrary lib : getLibraries()) {
+      if (lib.getTypes() != null) {
+        typesAccumulator.addAll(lib.getTypes());
+      }
+    }
+
+    List types = new LinkedList(typesAccumulator);
+    Collections.sort(types);
+
+    return types;
+  }
+
+  public ContributedLibrary getInstalled(String name) {
+    List installedReleases = new LinkedList(Collections2.filter(find(name), new InstalledPredicate()));
+    Collections.sort(installedReleases, new DownloadableContributionBuiltInAtTheBottomComparator());
+
+    if (installedReleases.isEmpty()) {
+      return null;
+    }
+
+    return installedReleases.get(0);
+  }
+}
diff --git a/arduino-core/src/cc/arduino/contributions/libraries/LibrariesIndexer.java b/arduino-core/src/cc/arduino/contributions/libraries/LibrariesIndexer.java
new file mode 100644
index 000000000..c285ade68
--- /dev/null
+++ b/arduino-core/src/cc/arduino/contributions/libraries/LibrariesIndexer.java
@@ -0,0 +1,223 @@
+/*
+ * This file is part of Arduino.
+ *
+ * Copyright 2014 Arduino LLC (http://www.arduino.cc/)
+ *
+ * Arduino 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * As a special exception, you may use this file as part of a free software
+ * library without restriction.  Specifically, if other files instantiate
+ * templates or use macros or inline functions from this file, or you compile
+ * this file and link it with other files to produce an executable, this
+ * file does not by itself cause the resulting executable to be covered by
+ * the GNU General Public License.  This exception does not however
+ * invalidate any other reasons why the executable file might be covered by
+ * the GNU General Public License.
+ */
+package cc.arduino.contributions.libraries;
+
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.module.mrbean.MrBeanModule;
+import processing.app.BaseNoGui;
+import processing.app.I18n;
+import processing.app.helpers.FileUtils;
+import processing.app.helpers.filefilters.OnlyDirs;
+import processing.app.packages.LegacyUserLibrary;
+import processing.app.packages.LibraryList;
+import processing.app.packages.UserLibrary;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.List;
+
+import static processing.app.I18n._;
+
+public class LibrariesIndexer {
+
+  private LibrariesIndex index;
+  private final LibraryList installedLibraries = new LibraryList();
+  private final LibraryList installedLibrariesWithDuplicates = new LibraryList();
+  private List librariesFolders;
+  private final File indexFile;
+  private final File stagingFolder;
+  private File sketchbookLibrariesFolder;
+
+  public LibrariesIndexer(File preferencesFolder) {
+    indexFile = new File(preferencesFolder, "library_index.json");
+    stagingFolder = new File(preferencesFolder, "staging" + File.separator +
+            "libraries");
+  }
+
+  public void parseIndex() throws IOException {
+    parseIndex(indexFile);
+    // TODO: resolve libraries inner references
+  }
+
+  private void parseIndex(File indexFile) throws IOException {
+    InputStream indexIn = null;
+    try {
+      indexIn = new FileInputStream(indexFile);
+      ObjectMapper mapper = new ObjectMapper();
+      mapper.registerModule(new MrBeanModule());
+      mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
+      mapper.configure(DeserializationFeature.EAGER_DESERIALIZER_FETCH, true);
+      mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+      index = mapper.readValue(indexIn, LibrariesIndex.class);
+
+      for (ContributedLibrary library : index.getLibraries()) {
+        if (library.getCategory() == null || "".equals(library.getCategory())) {
+          library.setCategory("Uncategorized");
+        }
+      }
+    } finally {
+      if (indexIn != null) {
+        indexIn.close();
+      }
+    }
+  }
+
+  public void setLibrariesFolders(List _librariesFolders) {
+    librariesFolders = _librariesFolders;
+    rescanLibraries();
+  }
+
+  public void rescanLibraries() {
+    // Clear all installed flags
+    installedLibraries.clear();
+    installedLibrariesWithDuplicates.clear();
+    for (ContributedLibrary lib : index.getLibraries())
+      lib.setInstalled(false);
+
+    // Rescan libraries
+    for (File folder : librariesFolders)
+      scanInstalledLibraries(folder, folder.equals(sketchbookLibrariesFolder));
+  }
+
+  private void scanInstalledLibraries(File folder, boolean isSketchbook) {
+    File list[] = folder.listFiles(OnlyDirs.ONLY_DIRS);
+    // if a bad folder or something like that, this might come back null
+    if (list == null)
+      return;
+
+    for (File subfolder : list) {
+      if (!BaseNoGui.isSanitaryName(subfolder.getName())) {
+        String mess = I18n.format(_("The library \"{0}\" 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)"),
+                subfolder.getName());
+        BaseNoGui.showMessage(_("Ignoring bad library name"), mess);
+        continue;
+      }
+
+      try {
+        scanLibrary(subfolder, isSketchbook);
+      } catch (IOException e) {
+        System.out.println(I18n.format(_("Invalid library found in {0}: {1}"), subfolder, e.getMessage()));
+      }
+    }
+  }
+
+  private void scanLibrary(File folder, boolean isSketchbook) throws IOException {
+    boolean readOnly = !FileUtils.isSubDirectory(sketchbookLibrariesFolder, folder);
+
+    // A library is considered "legacy" if it doesn't contains
+    // a file called "library.properties"
+    File check = new File(folder, "library.properties");
+    if (!check.exists() || !check.isFile()) {
+      // Create a legacy library and exit
+      LegacyUserLibrary lib = LegacyUserLibrary.create(folder);
+      lib.setReadOnly(readOnly);
+      installedLibraries.addOrReplace(lib);
+      if (isSketchbook) {
+        installedLibrariesWithDuplicates.add(lib);
+      } else {
+        installedLibrariesWithDuplicates.addOrReplace(lib);
+      }
+      return;
+    }
+
+    // Create a regular library
+    UserLibrary lib = UserLibrary.create(folder);
+    lib.setReadOnly(readOnly);
+    installedLibraries.addOrReplace(lib);
+    if (isSketchbook) {
+      installedLibrariesWithDuplicates.add(lib);
+    } else {
+      installedLibrariesWithDuplicates.addOrReplace(lib);
+    }
+
+    // Check if we can find the same library in the index
+    // and mark it as installed
+    ContributedLibrary foundLib = index.find(lib.getName(), lib.getParsedVersion());
+    if (foundLib != null) {
+      foundLib.setInstalled(true);
+      foundLib.setInstalledFolder(folder);
+      foundLib.setReadOnly(readOnly);
+      lib.setTypes(foundLib.getTypes());
+    }
+
+    if (lib.isReadOnly() && lib.getTypes() == null && !lib.getDeclaredTypes().isEmpty()) {
+      lib.setTypes(lib.getDeclaredTypes());
+    }
+
+    if (lib.getTypes() == null) {
+      lib.setTypes(Arrays.asList("Contributed"));
+    }
+  }
+
+  public LibrariesIndex getIndex() {
+    return index;
+  }
+
+  public LibraryList getInstalledLibraries() {
+    return installedLibraries;
+  }
+
+  // Same as getInstalledLibraries(), but allow duplicates between
+  // builtin+package libraries and sketchbook installed libraries.
+  // However, do not report duplicates among builtin and packages, to
+  // allow any package to override builtin libraries without being
+  // reported as duplicates.
+  public LibraryList getInstalledLibrariesWithDuplicates() {
+    return installedLibrariesWithDuplicates;
+  }
+
+  public File getStagingFolder() {
+    return stagingFolder;
+  }
+
+  /**
+   * Set the sketchbook library folder. 
+ * New libraries will be installed here.
+ * Libraries not found on this folder will be marked as read-only. + * + * @param folder + */ + public void setSketchbookLibrariesFolder(File folder) { + this.sketchbookLibrariesFolder = folder; + } + + public File getSketchbookLibrariesFolder() { + return sketchbookLibrariesFolder; + } + + public File getIndexFile() { + return indexFile; + } +} diff --git a/arduino-core/src/cc/arduino/contributions/libraries/LibraryInstaller.java b/arduino-core/src/cc/arduino/contributions/libraries/LibraryInstaller.java new file mode 100644 index 000000000..8da0ed9f2 --- /dev/null +++ b/arduino-core/src/cc/arduino/contributions/libraries/LibraryInstaller.java @@ -0,0 +1,172 @@ +/* + * This file is part of Arduino. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ +package cc.arduino.contributions.libraries; + +import cc.arduino.contributions.packages.DownloadableContributionsDownloader; +import cc.arduino.utils.ArchiveExtractor; +import cc.arduino.utils.MultiStepProgress; +import cc.arduino.utils.Progress; +import processing.app.BaseNoGui; +import processing.app.I18n; +import processing.app.helpers.FileUtils; + +import java.io.File; +import java.io.IOException; +import java.net.URL; + +import static processing.app.I18n._; + +public class LibraryInstaller { + + private static final String LIBRARY_INDEX_URL; + + static { + String externalLibraryIndexUrl = System.getProperty("LIBRARY_INDEX_URL"); + if (externalLibraryIndexUrl != null && !"".equals(externalLibraryIndexUrl)) { + LIBRARY_INDEX_URL = externalLibraryIndexUrl; + } else { + LIBRARY_INDEX_URL = "http://downloads.arduino.cc/libraries/library_index.json"; + } + } + + private final LibrariesIndexer indexer; + private final DownloadableContributionsDownloader downloader; + + public LibraryInstaller(LibrariesIndexer _indexer) { + indexer = _indexer; + File stagingFolder = _indexer.getStagingFolder(); + downloader = new DownloadableContributionsDownloader(stagingFolder) { + @Override + protected void onProgress(Progress progress) { + LibraryInstaller.this.onProgress(progress); + } + }; + } + + public void updateIndex() throws Exception { + final MultiStepProgress progress = new MultiStepProgress(2); + + // Step 1: Download index + URL url = new URL(LIBRARY_INDEX_URL); + File outputFile = indexer.getIndexFile(); + File tmpFile = new File(outputFile.getAbsolutePath() + ".tmp"); + try { + downloader.download(url, tmpFile, progress, + _("Downloading libraries index...")); + } catch (InterruptedException e) { + // Download interrupted... just exit + return; + } + progress.stepDone(); + + // TODO: Check downloaded index + + // Replace old index with the updated one + if (outputFile.exists()) + outputFile.delete(); + if (!tmpFile.renameTo(outputFile)) + throw new Exception( + _("An error occurred while updating libraries index!")); + + // Step 2: Rescan index + rescanLibraryIndex(progress); + } + + public void install(ContributedLibrary lib, ContributedLibrary replacedLib) throws Exception { + if (lib.isInstalled()) { + System.out.println(I18n.format(_("Library is already installed: {0} version {1}"), lib.getName(), lib.getParsedVersion())); + return; + } + + final MultiStepProgress progress = new MultiStepProgress(3); + + // Step 1: Download library + try { + downloader.download(lib, progress, I18n.format(_("Downloading library: {0}"), lib.getName())); + } catch (InterruptedException e) { + // Download interrupted... just exit + return; + } + + // TODO: Extract to temporary folders and move to the final destination only + // once everything is successfully unpacked. If the operation fails remove + // all the temporary folders and abort installation. + + // Step 2: Unpack library on the correct location + progress.setStatus(I18n.format(_("Installing library: {0}"), lib.getName())); + onProgress(progress); + File libsFolder = indexer.getSketchbookLibrariesFolder(); + File tmpFolder = FileUtils.createTempFolderIn(libsFolder); + try { + new ArchiveExtractor(BaseNoGui.getPlatform()).extract(lib.getDownloadedFile(), tmpFolder, 1); + } catch (Exception e) { + if (tmpFolder.exists()) + FileUtils.recursiveDelete(tmpFolder); + } + progress.stepDone(); + + // Step 3: Remove replaced library and move installed one to the correct location + // TODO: Fix progress bar... + remove(replacedLib); + File destFolder = new File(libsFolder, lib.getName().replaceAll(" ", "_")); + tmpFolder.renameTo(destFolder); + progress.stepDone(); + + // Step 4: Rescan index + rescanLibraryIndex(progress); + } + + public void remove(ContributedLibrary lib) throws IOException { + if (lib == null || lib.isReadOnly()) { + return; + } + + final MultiStepProgress progress = new MultiStepProgress(2); + + // Step 1: Remove library + progress.setStatus(I18n.format(_("Removing library: {0}"), lib.getName())); + onProgress(progress); + FileUtils.recursiveDelete(lib.getInstalledFolder()); + progress.stepDone(); + + // Step 2: Rescan index + rescanLibraryIndex(progress); + } + + private void rescanLibraryIndex(MultiStepProgress progress) { + progress.setStatus(_("Updating list of installed libraries")); + onProgress(progress); + indexer.rescanLibraries(); + progress.stepDone(); + } + + protected void onProgress(Progress progress) { + // Empty + } +} diff --git a/arduino-core/src/cc/arduino/contributions/libraries/filters/LibraryWithNamePredicate.java b/arduino-core/src/cc/arduino/contributions/libraries/filters/LibraryWithNamePredicate.java new file mode 100644 index 000000000..a1cc5090f --- /dev/null +++ b/arduino-core/src/cc/arduino/contributions/libraries/filters/LibraryWithNamePredicate.java @@ -0,0 +1,48 @@ +/* + * This file is part of Arduino. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ + +package cc.arduino.contributions.libraries.filters; + +import cc.arduino.contributions.libraries.ContributedLibrary; +import com.google.common.base.Predicate; + +public class LibraryWithNamePredicate implements Predicate { + + private final String name; + + public LibraryWithNamePredicate(String name) { + this.name = name; + } + + @Override + public boolean apply(ContributedLibrary contributedLibrary) { + return name.equals(contributedLibrary.getName()); + } + +} diff --git a/arduino-core/src/cc/arduino/contributions/packages/Constants.java b/arduino-core/src/cc/arduino/contributions/packages/Constants.java new file mode 100644 index 000000000..1afbe0075 --- /dev/null +++ b/arduino-core/src/cc/arduino/contributions/packages/Constants.java @@ -0,0 +1,23 @@ +package cc.arduino.contributions.packages; + +import java.util.Arrays; +import java.util.List; + +public class Constants { + + public static final String DEFAULT_INDEX_FILE_NAME = "package_index.json"; + public static final List PROTECTED_PACKAGE_NAMES = Arrays.asList("arduino", "Intel"); + public static final String PACKAGE_INDEX_URL; + + public static final String PREFERENCES_BOARDS_MANAGER_ADDITIONAL_URLS = "boardsmanager.additional.urls"; + + static { + String extenalPackageIndexUrl = System.getProperty("PACKAGE_INDEX_URL"); + if (extenalPackageIndexUrl != null && !"".equals(extenalPackageIndexUrl)) { + PACKAGE_INDEX_URL = extenalPackageIndexUrl; + } else { + PACKAGE_INDEX_URL = "http://downloads.arduino.cc/packages/package_index.json"; + } + } + +} diff --git a/arduino-core/src/cc/arduino/contributions/packages/ContributedBoard.java b/arduino-core/src/cc/arduino/contributions/packages/ContributedBoard.java new file mode 100644 index 000000000..9a115ad8d --- /dev/null +++ b/arduino-core/src/cc/arduino/contributions/packages/ContributedBoard.java @@ -0,0 +1,35 @@ +/* + * This file is part of Arduino. + * + * Copyright 2014 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ +package cc.arduino.contributions.packages; + +public interface ContributedBoard { + + String getName(); + +} diff --git a/arduino-core/src/cc/arduino/contributions/packages/ContributedHelp.java b/arduino-core/src/cc/arduino/contributions/packages/ContributedHelp.java new file mode 100644 index 000000000..1c13a2d7f --- /dev/null +++ b/arduino-core/src/cc/arduino/contributions/packages/ContributedHelp.java @@ -0,0 +1,7 @@ +package cc.arduino.contributions.packages; + +public abstract class ContributedHelp { + + public abstract String getOnline(); + +} diff --git a/arduino-core/src/cc/arduino/contributions/packages/ContributedPackage.java b/arduino-core/src/cc/arduino/contributions/packages/ContributedPackage.java new file mode 100644 index 000000000..18e8d58a5 --- /dev/null +++ b/arduino-core/src/cc/arduino/contributions/packages/ContributedPackage.java @@ -0,0 +1,101 @@ +/* + * This file is part of Arduino. + * + * Copyright 2014 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ +package cc.arduino.contributions.packages; + +import cc.arduino.contributions.VersionComparator; + +import java.util.List; + +public abstract class ContributedPackage { + + public abstract String getName(); + + public abstract String getMaintainer(); + + public abstract String getWebsiteURL(); + + public abstract String getEmail(); + + public abstract List getPlatforms(); + + public abstract List getTools(); + + public abstract ContributedHelp getHelp(); + + public ContributedPlatform findPlatform(String architecture, String version) { + if (architecture == null || version == null) { + return null; + } + for (ContributedPlatform platform : getPlatforms()) { + if (platform.getArchitecture().equals(architecture) && version.equals(platform.getParsedVersion())) + return platform; + } + return null; + } + + public ContributedTool findTool(String name, String version) { + for (ContributedTool tool : getTools()) { + if (tool.getName().equals(name) && tool.getVersion().equals(version)) + return tool; + } + return null; + } + + @Override + public String toString() { + String res; + res = "Package name : " + getName() + "\n"; + res += " maintaner : " + getMaintainer() + " (" + getEmail() + ")\n"; + if (getPlatforms() != null) { + for (ContributedPlatform plat : getPlatforms()) { + res += "\n Plaform : name : " + plat.getName(); + if (plat.isInstalled()) { + res += "\n " + plat; + } + res += "\n category : " + plat.getCategory(); + res += "\n architecture : " + + plat.getArchitecture() + " " + plat.getParsedVersion() + "\n"; + if (plat.getToolsDependencies() != null) + for (ContributedToolReference t : plat.getToolsDependencies()) { + res += " tool dep : " + t.getName() + " " + + t.getVersion() + "\n"; + } + if (plat.getBoards() != null) + for (ContributedBoard board : plat.getBoards()) + res += " board : " + board.getName() + + "\n"; + } + } + if (getTools() != null) { + for (ContributedTool tool : getTools()) + res += tool + "\n"; + } + return res; + } +} diff --git a/arduino-core/src/cc/arduino/contributions/packages/ContributedPlatform.java b/arduino-core/src/cc/arduino/contributions/packages/ContributedPlatform.java new file mode 100644 index 000000000..83565f912 --- /dev/null +++ b/arduino-core/src/cc/arduino/contributions/packages/ContributedPlatform.java @@ -0,0 +1,96 @@ +/* + * This file is part of Arduino. + * + * Copyright 2014 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ +package cc.arduino.contributions.packages; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; + +public abstract class ContributedPlatform extends DownloadableContribution { + + public abstract String getName(); + + public abstract String getCategory(); + + public abstract void setCategory(String category); + + public abstract String getArchitecture(); + + public abstract String getChecksum(); + + public abstract List getToolsDependencies(); + + public abstract List getBoards(); + + public abstract ContributedHelp getHelp(); + + private List resolvedTools = null; + + private ContributedPackage parentPackage; + + public List getResolvedTools() { + if (resolvedTools == null) { + return null; + } + return new LinkedList(resolvedTools); + } + + public void resolveToolsDependencies(Collection packages) { + resolvedTools = new ArrayList(); + + // If there are no dependencies return empty list + if (getToolsDependencies() == null) { + return; + } + + // For each tool dependency + for (ContributedToolReference dep : getToolsDependencies()) { + // Search the referenced tool + ContributedTool tool = dep.resolve(packages); + if (tool == null) { + System.err.println("Index error: could not find referenced tool " + dep); + } + resolvedTools.add(tool); + } + } + + public ContributedPackage getParentPackage() { + return parentPackage; + } + + public void setParentPackage(ContributedPackage parentPackage) { + this.parentPackage = parentPackage; + } + + @Override + public String toString() { + return getParsedVersion(); + } +} diff --git a/arduino-core/src/cc/arduino/contributions/packages/ContributedTargetPackage.java b/arduino-core/src/cc/arduino/contributions/packages/ContributedTargetPackage.java new file mode 100644 index 000000000..1a481a5a2 --- /dev/null +++ b/arduino-core/src/cc/arduino/contributions/packages/ContributedTargetPackage.java @@ -0,0 +1,85 @@ +/* + * This file is part of Arduino. + * + * Copyright 2014 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ +package cc.arduino.contributions.packages; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import processing.app.debug.TargetPackage; +import processing.app.debug.TargetPlatform; + +public class ContributedTargetPackage implements TargetPackage { + + private final String id; + private final Map platforms; + + public ContributedTargetPackage(String _id) { + id = _id; + platforms = new HashMap(); + } + + void addPlatform(TargetPlatform p) { + platforms.put(p.getId(), p); + } + + boolean hasPlatforms() { + return platforms.size() > 0; + } + + @Override + public String getId() { + return id; + } + + @Override + public Map getPlatforms() { + return platforms; + } + + @Override + public Collection platforms() { + return platforms.values(); + } + + @Override + public TargetPlatform get(String platform) { + return platforms.get(platform); + } + + @Override + public boolean hasPlatform(TargetPlatform platform) { + return platforms.containsKey(platform.getId()); + } + + @Override + public String toString() { + return "TargetPackage: " + getId(); + } +} diff --git a/arduino-core/src/cc/arduino/contributions/packages/ContributedTargetPlatform.java b/arduino-core/src/cc/arduino/contributions/packages/ContributedTargetPlatform.java new file mode 100644 index 000000000..b7e1a0681 --- /dev/null +++ b/arduino-core/src/cc/arduino/contributions/packages/ContributedTargetPlatform.java @@ -0,0 +1,45 @@ +/* + * This file is part of Arduino. + * + * Copyright 2014 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ +package cc.arduino.contributions.packages; + +import java.io.File; + +import processing.app.debug.LegacyTargetPlatform; +import processing.app.debug.TargetPackage; +import processing.app.debug.TargetPlatformException; + +public class ContributedTargetPlatform extends LegacyTargetPlatform { + + public ContributedTargetPlatform(String _name, File _folder, + TargetPackage parent, + ContributionsIndex index) + throws TargetPlatformException { + super(_name, _folder, parent); + } +} diff --git a/arduino-core/src/cc/arduino/contributions/packages/ContributedTool.java b/arduino-core/src/cc/arduino/contributions/packages/ContributedTool.java new file mode 100644 index 000000000..a8f346b79 --- /dev/null +++ b/arduino-core/src/cc/arduino/contributions/packages/ContributedTool.java @@ -0,0 +1,63 @@ +/* + * This file is part of Arduino. + * + * Copyright 2014 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ +package cc.arduino.contributions.packages; + +import processing.app.BaseNoGui; + +import java.util.List; + +public abstract class ContributedTool { + + public abstract String getName(); + + public abstract String getVersion(); + + public abstract List getSystems(); + + public DownloadableContribution getDownloadableContribution() { + for (HostDependentDownloadableContribution c : getSystems()) { + if (c.isCompatible(BaseNoGui.getPlatform())) + return c; + } + return null; + } + + @Override + public String toString() { + String res; + res = "Tool name : " + getName() + " " + getVersion() + "\n"; + for (HostDependentDownloadableContribution sys : getSystems()) { + res += " sys"; + res += sys.isCompatible(BaseNoGui.getPlatform()) ? "*" : " "; + res += " : " + sys + "\n"; + } + return res; + } + +} diff --git a/arduino-core/src/cc/arduino/contributions/packages/ContributedToolReference.java b/arduino-core/src/cc/arduino/contributions/packages/ContributedToolReference.java new file mode 100644 index 000000000..ef4c808a8 --- /dev/null +++ b/arduino-core/src/cc/arduino/contributions/packages/ContributedToolReference.java @@ -0,0 +1,57 @@ +/* + * This file is part of Arduino. + * + * Copyright 2014 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ +package cc.arduino.contributions.packages; + +import java.util.Collection; + +public abstract class ContributedToolReference { + + public abstract String getName(); + + public abstract String getVersion(); + + public abstract String getPackager(); + + public ContributedTool resolve(Collection packages) { + for (ContributedPackage pack : packages) { + for (ContributedTool tool : pack.getTools()) + if (tool.getName().equals(getName()) && + tool.getVersion().equals(getVersion()) && + pack.getName().equals(getPackager())) + return tool; + } + return null; + } + + @Override + public String toString() { + return "name=" + getName() + " version=" + getVersion() + " packager=" + + getPackager(); + } +} \ No newline at end of file diff --git a/arduino-core/src/cc/arduino/contributions/packages/ContributionInstaller.java b/arduino-core/src/cc/arduino/contributions/packages/ContributionInstaller.java new file mode 100644 index 000000000..c083193ee --- /dev/null +++ b/arduino-core/src/cc/arduino/contributions/packages/ContributionInstaller.java @@ -0,0 +1,302 @@ +/* + * This file is part of Arduino. + * + * Copyright 2014 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ +package cc.arduino.contributions.packages; + +import cc.arduino.contributions.GPGDetachedSignatureVerifier; +import cc.arduino.filters.FileExecutablePredicate; +import cc.arduino.utils.ArchiveExtractor; +import cc.arduino.utils.MultiStepProgress; +import cc.arduino.utils.Progress; +import com.google.common.collect.Collections2; +import org.apache.commons.exec.CommandLine; +import org.apache.commons.exec.Executor; +import processing.app.BaseNoGui; +import processing.app.I18n; +import processing.app.PreferencesData; +import processing.app.helpers.FileUtils; +import processing.app.helpers.filefilters.OnlyDirs; +import processing.app.tools.CollectStdOutStdErrExecutor; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.util.*; + +import static processing.app.I18n._; +import static processing.app.I18n.format; + +public class ContributionInstaller { + + private final ContributionsIndexer indexer; + private final DownloadableContributionsDownloader downloader; + + public ContributionInstaller(ContributionsIndexer contributionsIndexer) { + File stagingFolder = contributionsIndexer.getStagingFolder(); + indexer = contributionsIndexer; + downloader = new DownloadableContributionsDownloader(stagingFolder) { + @Override + protected void onProgress(Progress progress) { + ContributionInstaller.this.onProgress(progress); + } + }; + } + + public List install(ContributedPlatform platform) throws Exception { + List errors = new LinkedList(); + if (platform.isInstalled()) { + throw new Exception("Platform is already installed!"); + } + + // Do not download already installed tools + List tools = new LinkedList(platform.getResolvedTools()); + Iterator toolsIterator = tools.iterator(); + while (toolsIterator.hasNext()) { + ContributedTool tool = toolsIterator.next(); + DownloadableContribution downloadable = tool.getDownloadableContribution(); + if (downloadable == null) { + throw new Exception(format(_("Tool {0} is not available for your operating system."), tool.getName())); + } + if (downloadable.isInstalled()) { + toolsIterator.remove(); + } + } + + // Calculate progress increases + MultiStepProgress progress = new MultiStepProgress((tools.size() + 1) * 2); + + // Download all + try { + // Download platform + downloader.download(platform, progress, _("Downloading boards definitions.")); + progress.stepDone(); + + // Download tools + int i = 1; + for (ContributedTool tool : tools) { + String msg = format(_("Downloading tools ({0}/{1})."), i, tools.size()); + i++; + downloader.download(tool.getDownloadableContribution(), progress, msg); + progress.stepDone(); + } + } catch (InterruptedException e) { + // Download interrupted... just exit + return errors; + } + + ContributedPackage pack = platform.getParentPackage(); + File packageFolder = new File(indexer.getPackagesFolder(), pack.getName()); + + // TODO: Extract to temporary folders and move to the final destination only + // once everything is successfully unpacked. If the operation fails remove + // all the temporary folders and abort installation. + + // Unzip tools on the correct location + File toolsFolder = new File(packageFolder, "tools"); + int i = 1; + for (ContributedTool tool : tools) { + progress.setStatus(format(_("Installing tools ({0}/{1})..."), i, tools.size())); + onProgress(progress); + i++; + DownloadableContribution toolContrib = tool.getDownloadableContribution(); + File destFolder = new File(toolsFolder, tool.getName() + File.separator + tool.getVersion()); + + destFolder.mkdirs(); + assert toolContrib.getDownloadedFile() != null; + new ArchiveExtractor(BaseNoGui.getPlatform()).extract(toolContrib.getDownloadedFile(), destFolder, 1); + try { + executePostInstallScriptIfAny(destFolder); + } catch (IOException e) { + errors.add(_("Error running post install script")); + } + toolContrib.setInstalled(true); + toolContrib.setInstalledFolder(destFolder); + progress.stepDone(); + } + + // Unpack platform on the correct location + progress.setStatus(_("Installing boards...")); + onProgress(progress); + File platformFolder = new File(packageFolder, "hardware" + File.separator + platform.getArchitecture()); + File destFolder = new File(platformFolder, platform.getParsedVersion()); + destFolder.mkdirs(); + new ArchiveExtractor(BaseNoGui.getPlatform()).extract(platform.getDownloadedFile(), destFolder, 1); + platform.setInstalled(true); + platform.setInstalledFolder(destFolder); + progress.stepDone(); + + progress.setStatus(_("Installation completed!")); + onProgress(progress); + + return errors; + } + + private void executePostInstallScriptIfAny(File folder) throws IOException { + Collection postInstallScripts = Collections2.filter(BaseNoGui.getPlatform().postInstallScripts(folder), new FileExecutablePredicate()); + + if (postInstallScripts.isEmpty()) { + String[] subfolders = folder.list(new OnlyDirs()); + if (subfolders.length != 1) { + return; + } + + executePostInstallScriptIfAny(new File(folder, subfolders[0])); + return; + } + + File postInstallScript = postInstallScripts.iterator().next(); + + ByteArrayOutputStream stdout = new ByteArrayOutputStream(); + ByteArrayOutputStream stderr = new ByteArrayOutputStream(); + Executor executor = new CollectStdOutStdErrExecutor(stdout, stderr); + executor.setWorkingDirectory(folder); + executor.setExitValues(null); + int exitValue = executor.execute(new CommandLine(postInstallScript)); + executor.setExitValues(new int[0]); + + System.out.write(stdout.toByteArray()); + System.err.write(stderr.toByteArray()); + + if (executor.isFailure(exitValue)) { + throw new IOException(); + } + } + + public List remove(ContributedPlatform platform) { + if (platform == null || platform.isReadOnly()) { + return new LinkedList(); + } + List errors = new LinkedList(); + FileUtils.recursiveDelete(platform.getInstalledFolder()); + platform.setInstalled(false); + platform.setInstalledFolder(null); + + // Check if the tools are no longer needed + for (ContributedTool tool : platform.getResolvedTools()) { + if (indexer.isContributedToolUsed(tool)) { + continue; + } + + DownloadableContribution toolContrib = tool.getDownloadableContribution(); + File destFolder = toolContrib.getInstalledFolder(); + FileUtils.recursiveDelete(destFolder); + toolContrib.setInstalled(false); + toolContrib.setInstalledFolder(null); + + // We removed the version folder (.../tools/TOOL_NAME/VERSION) + // now try to remove the containing TOOL_NAME folder + // (and silently fail if another version of the tool is installed) + try { + destFolder.getParentFile().delete(); + } catch (SecurityException e) { + // ignore + } + } + + return errors; + } + + public List updateIndex() throws Exception { + MultiStepProgress progress = new MultiStepProgress(1); + + List downloadedPackageIndexFilesAccumulator = new LinkedList(); + downloadIndexAndSignature(progress, downloadedPackageIndexFilesAccumulator, Constants.PACKAGE_INDEX_URL); + + Set packageIndexURLs = new HashSet(); + String additionalURLs = PreferencesData.get(Constants.PREFERENCES_BOARDS_MANAGER_ADDITIONAL_URLS, ""); + if (!"".equals(additionalURLs)) { + packageIndexURLs.addAll(Arrays.asList(additionalURLs.split(","))); + } + + for (String packageIndexURL : packageIndexURLs) { + downloadIndexAndSignature(progress, downloadedPackageIndexFilesAccumulator, packageIndexURL); + } + + progress.stepDone(); + + return downloadedPackageIndexFilesAccumulator; + } + + private void downloadIndexAndSignature(MultiStepProgress progress, List downloadedPackagedIndexFilesAccumulator, String packageIndexUrl) throws Exception { + File packageIndex = download(progress, packageIndexUrl); + downloadedPackagedIndexFilesAccumulator.add(packageIndex.getName()); + try { + File packageIndexSignature = download(progress, packageIndexUrl + ".sig"); + boolean signatureVerified = new GPGDetachedSignatureVerifier().verify(packageIndex, packageIndexSignature, new File(BaseNoGui.getContentFile("lib"), "public.gpg.key")); + if (signatureVerified) { + downloadedPackagedIndexFilesAccumulator.add(packageIndexSignature.getName()); + } else { + downloadedPackagedIndexFilesAccumulator.remove(packageIndex.getName()); + packageIndex.delete(); + packageIndexSignature.delete(); + System.err.println(I18n.format(_("{0} file signature verification failed. File ignored."), packageIndexUrl)); + } + } catch (Exception e) { + //ignore errors + } + } + + private File download(MultiStepProgress progress, String packageIndexUrl) throws Exception { + String statusText = _("Downloading platforms index..."); + URL url = new URL(packageIndexUrl); + String[] urlPathParts = url.getFile().split("/"); + File outputFile = indexer.getIndexFile(urlPathParts[urlPathParts.length - 1]); + File tmpFile = new File(outputFile.getAbsolutePath() + ".tmp"); + downloader.download(url, tmpFile, progress, statusText); + + // Replace old index with the updated one + if (outputFile.exists()) { + if (!outputFile.delete()) { + throw new Exception("An error occurred while updating platforms index! I can't delete file " + outputFile); + } + } + if (!tmpFile.renameTo(outputFile)) { + throw new Exception("An error occurred while updating platforms index! I can't rename file " + tmpFile); + } + + return outputFile; + } + + protected void onProgress(Progress progress) { + // Empty + } + + public void deleteUnknownFiles(List downloadedPackageIndexFiles) { + File preferencesFolder = indexer.getIndexFile(".").getParentFile(); + File[] additionalPackageIndexFiles = preferencesFolder.listFiles(new PackageIndexFilenameFilter(Constants.DEFAULT_INDEX_FILE_NAME)); + if (additionalPackageIndexFiles == null) { + return; + } + for (File additionalPackageIndexFile : additionalPackageIndexFiles) { + if (!downloadedPackageIndexFiles.contains(additionalPackageIndexFile.getName())) { + additionalPackageIndexFile.delete(); + } + } + } +} diff --git a/arduino-core/src/cc/arduino/contributions/packages/ContributionsIndex.java b/arduino-core/src/cc/arduino/contributions/packages/ContributionsIndex.java new file mode 100644 index 000000000..1804e719f --- /dev/null +++ b/arduino-core/src/cc/arduino/contributions/packages/ContributionsIndex.java @@ -0,0 +1,151 @@ +/* + * This file is part of Arduino. + * + * Copyright 2014 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ +package cc.arduino.contributions.packages; + +import cc.arduino.contributions.DownloadableContributionBuiltInAtTheBottomComparator; +import cc.arduino.contributions.filters.DownloadableContributionWithVersionPredicate; +import cc.arduino.contributions.filters.InstalledPredicate; +import cc.arduino.contributions.packages.filters.PlatformArchitecturePredicate; +import com.google.common.base.Function; +import com.google.common.collect.Collections2; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; + +import java.util.*; + +public abstract class ContributionsIndex { + + public abstract List getPackages(); + + public ContributedPackage findPackage(String packageName) { + for (ContributedPackage pack : getPackages()) { + if (pack.getName().equals(packageName)) + return pack; + } + return null; + } + + public List findPlatforms(String packageName, final String platformArch) { + if (packageName == null || platformArch == null) { + return null; + + } + ContributedPackage aPackage = findPackage(packageName); + if (aPackage == null) { + return null; + } + Collection platforms = Collections2.filter(aPackage.getPlatforms(), new PlatformArchitecturePredicate(platformArch)); + return Lists.newLinkedList(platforms); + } + + public ContributedPlatform findPlatform(String packageName, final String platformArch, final String platformVersion) { + if (platformVersion == null) { + return null; + + } + + Collection platformsByName = findPlatforms(packageName, platformArch); + if (platformsByName == null) { + return null; + } + + Collection platforms = Collections2.filter(platformsByName, new DownloadableContributionWithVersionPredicate(platformVersion)); + if (platforms.isEmpty()) { + return null; + } + + return platforms.iterator().next(); + } + + public ContributedPlatform getInstalled(String packageName, String platformArch) { + List installedPlatforms = new LinkedList(Collections2.filter(findPlatforms(packageName, platformArch), new InstalledPredicate())); + Collections.sort(installedPlatforms, new DownloadableContributionBuiltInAtTheBottomComparator()); + + if (installedPlatforms.isEmpty()) { + return null; + } + + return installedPlatforms.get(0); + } + + public List getPlatforms() { + return Lists.newLinkedList(Iterables.concat(Collections2.transform(getPackages(), new Function>() { + @Override + public List apply(ContributedPackage contributedPackage) { + return contributedPackage.getPlatforms(); + } + }))); + } + + + public ContributedTool findTool(String packageName, String name, + String version) { + ContributedPackage pack = findPackage(packageName); + if (pack == null) + return null; + return pack.findTool(name, version); + } + + private final List categories = new ArrayList(); + + public List getCategories() { + return categories; + } + + public void fillCategories() { + categories.clear(); + for (ContributedPackage pack : getPackages()) { + for (ContributedPlatform platform : pack.getPlatforms()) { + if (!categories.contains(platform.getCategory())) + categories.add(platform.getCategory()); + } + } + } + + public ContributedPackage getPackage(String packageName) { + for (ContributedPackage pack : getPackages()) { + if (pack.getName().equals(packageName)) { + return pack; + } + } + return null; + } + + @Override + public String toString() { + String res = ""; + res += "Categories: "; + for (String c : getCategories()) + res += "'" + c + "' "; + res += "\n"; + for (ContributedPackage pack : getPackages()) + res += pack + "\n"; + return res; + } +} diff --git a/arduino-core/src/cc/arduino/contributions/packages/ContributionsIndexer.java b/arduino-core/src/cc/arduino/contributions/packages/ContributionsIndexer.java new file mode 100644 index 000000000..fd26b7e68 --- /dev/null +++ b/arduino-core/src/cc/arduino/contributions/packages/ContributionsIndexer.java @@ -0,0 +1,403 @@ +/* + * This file is part of Arduino. + * + * Copyright 2014 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ +package cc.arduino.contributions.packages; + +import cc.arduino.contributions.DownloadableContributionBuiltInAtTheBottomComparator; +import cc.arduino.contributions.GPGDetachedSignatureVerifier; +import cc.arduino.contributions.SignatureVerificationFailedException; +import cc.arduino.contributions.filters.BuiltInPredicate; +import cc.arduino.contributions.filters.InstalledPredicate; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.module.mrbean.MrBeanModule; +import com.google.common.base.Function; +import com.google.common.base.Predicates; +import com.google.common.collect.Collections2; +import com.google.common.collect.ImmutableListMultimap; +import com.google.common.collect.Multimaps; +import processing.app.BaseNoGui; +import processing.app.debug.TargetPackage; +import processing.app.debug.TargetPlatform; +import processing.app.debug.TargetPlatformException; +import processing.app.helpers.PreferencesMap; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.*; + +import static processing.app.helpers.filefilters.OnlyDirs.ONLY_DIRS; + +public class ContributionsIndexer { + + private final File packagesFolder; + private final File stagingFolder; + private final File preferencesFolder; + private ContributionsIndex index; + + public ContributionsIndexer(File preferencesFolder) { + this.preferencesFolder = preferencesFolder; + packagesFolder = new File(preferencesFolder, "packages"); + stagingFolder = new File(preferencesFolder, "staging" + File.separator + "packages"); + } + + public void parseIndex() throws Exception { + File defaultIndexFile = getIndexFile(Constants.DEFAULT_INDEX_FILE_NAME); + if (!isSigned(defaultIndexFile)) { + throw new SignatureVerificationFailedException(Constants.DEFAULT_INDEX_FILE_NAME); + } + index = parseIndex(defaultIndexFile); + + File[] indexFiles = preferencesFolder.listFiles(new TestPackageIndexFilenameFilter(new PackageIndexFilenameFilter(Constants.DEFAULT_INDEX_FILE_NAME))); + + for (File indexFile : indexFiles) { + ContributionsIndex contributionsIndex = parseIndex(indexFile); + mergeContributions(contributionsIndex, indexFile); + } + + List packages = index.getPackages(); + for (ContributedPackage pack : packages) { + for (ContributedPlatform platform : pack.getPlatforms()) { + // Set a reference to parent packages + platform.setParentPackage(pack); + + // Resolve tools dependencies (works also as a check for file integrity) + platform.resolveToolsDependencies(packages); + } + } + + index.fillCategories(); + } + + private void mergeContributions(ContributionsIndex contributionsIndex, File indexFile) { + boolean signed = isSigned(indexFile); + + for (ContributedPackage contributedPackage : contributionsIndex.getPackages()) { + if (!signed) { + for (ContributedPlatform contributedPlatform : contributedPackage.getPlatforms()) { + contributedPlatform.setCategory("Contributed"); + } + } + + ContributedPackage targetPackage = index.getPackage(contributedPackage.getName()); + + if (targetPackage == null) { + index.getPackages().add(contributedPackage); + } else { + if (signed || !isPackageNameProtected(contributedPackage)) { + List platforms = contributedPackage.getPlatforms(); + if (platforms == null) { + platforms = new LinkedList(); + } + for (ContributedPlatform contributedPlatform : platforms) { + ContributedPlatform platform = targetPackage.findPlatform(contributedPlatform.getArchitecture(), contributedPlatform.getVersion()); + if (platform != null) { + targetPackage.getPlatforms().remove(platform); + } + targetPackage.getPlatforms().add(contributedPlatform); + } + List tools = contributedPackage.getTools(); + if (tools == null) { + tools = new LinkedList(); + } + for (ContributedTool contributedTool : tools) { + ContributedTool tool = targetPackage.findTool(contributedTool.getName(), contributedTool.getVersion()); + if (tool != null) { + targetPackage.getTools().remove(tool); + } + targetPackage.getTools().add(contributedTool); + } + } + } + } + } + + private boolean isPackageNameProtected(ContributedPackage contributedPackage) { + return Constants.PROTECTED_PACKAGE_NAMES.contains(contributedPackage.getName()); + } + + private boolean isSigned(File indexFile) { + File signature = new File(indexFile.getParent(), indexFile.getName() + ".sig"); + if (!signature.exists()) { + return false; + } + + try { + return new GPGDetachedSignatureVerifier().verify(indexFile, signature, new File(BaseNoGui.getContentFile("lib"), "public.gpg.key")); + } catch (Exception e) { + BaseNoGui.showWarning(e.getMessage(), e.getMessage(), e); + return false; + } + } + + private ContributionsIndex parseIndex(File indexFile) throws IOException { + InputStream inputStream = null; + try { + inputStream = new FileInputStream(indexFile); + ObjectMapper mapper = new ObjectMapper(); + mapper.registerModule(new MrBeanModule()); + mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true); + mapper.configure(DeserializationFeature.EAGER_DESERIALIZER_FETCH, true); + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + return mapper.readValue(inputStream, ContributionsIndex.class); + } finally { + if (inputStream != null) { + inputStream.close(); + } + } + } + + public void syncWithFilesystem(File hardwareFolder) throws IOException { + syncBuiltInHardwareFolder(hardwareFolder); + + syncLocalPackagesFolder(); + } + + public void syncBuiltInHardwareFolder(File hardwareFolder) throws IOException { + if (index == null) { + return; + } + for (File folder : hardwareFolder.listFiles(ONLY_DIRS)) { + ContributedPackage pack = index.findPackage(folder.getName()); + if (pack != null) { + syncBuiltInPackageWithFilesystem(pack, folder); + + File toolsFolder = new File(hardwareFolder, "tools"); + if (toolsFolder.isDirectory()) { + for (File toolFolder : toolsFolder.listFiles(ONLY_DIRS)) { + File builtInToolsMetadata = new File(toolFolder, "builtin_tools_versions.txt"); + if (builtInToolsMetadata.isFile()) { + PreferencesMap toolsMetadata = new PreferencesMap(builtInToolsMetadata).subTree(pack.getName()); + for (Map.Entry toolMetadata : toolsMetadata.entrySet()) { + syncToolWithFilesystem(pack, toolFolder, toolMetadata.getKey(), toolMetadata.getValue()); + } + } + } + } + } + } + } + + private void syncBuiltInPackageWithFilesystem(ContributedPackage pack, File hardwareFolder) throws IOException { + // Scan all hardware folders and mark as installed all the tools found. + for (File platformFolder : hardwareFolder.listFiles(ONLY_DIRS)) { + File platformTxt = new File(platformFolder, "platform.txt"); + String version = new PreferencesMap(platformTxt).get("version"); + ContributedPlatform platform = syncHardwareWithFilesystem(pack, platformFolder, platformFolder.getName(), version); + if (platform != null) { + platform.setReadOnly(true); + } + } + } + + public void syncLocalPackagesFolder() { + if (!packagesFolder.isDirectory()) { + return; + } + + if (index == null) { + return; + } + + // Scan all hardware folders and mark as installed all the + // platforms found. + for (File folder : packagesFolder.listFiles(ONLY_DIRS)) { + ContributedPackage pack = index.findPackage(folder.getName()); + if (pack != null) { + syncPackageWithFilesystem(pack, folder); + } + } + } + + private void syncPackageWithFilesystem(ContributedPackage pack, File root) { + // Scan all hardware folders and mark as installed all the tools found. + File hardwareFolder = new File(root, "hardware"); + if (hardwareFolder.isDirectory()) { + for (File platformFolder : hardwareFolder.listFiles(ONLY_DIRS)) { + for (File versionFolder : platformFolder.listFiles(ONLY_DIRS)) { + syncHardwareWithFilesystem(pack, versionFolder, platformFolder.getName(), versionFolder.getName()); + } + } + } + + // Scan all tools folders and mark as installed all the tools found. + File toolsFolder = new File(root, "tools"); + if (toolsFolder.isDirectory()) { + for (File toolFolder : toolsFolder.listFiles(ONLY_DIRS)) { + for (File versionFolder : toolFolder.listFiles(ONLY_DIRS)) { + syncToolWithFilesystem(pack, versionFolder, toolFolder.getName(), versionFolder.getName()); + } + } + } + } + + private void syncToolWithFilesystem(ContributedPackage pack, File installationFolder, String toolName, String version) { + ContributedTool tool = pack.findTool(toolName, version); + if (tool == null) { + return; + } + DownloadableContribution contrib = tool.getDownloadableContribution(); + if (contrib == null) { + System.err.println(tool + " seems to have no downloadable contributions for your operating system, but it is installed in\n" + installationFolder); + return; + } + contrib.setInstalled(true); + contrib.setInstalledFolder(installationFolder); + } + + private ContributedPlatform syncHardwareWithFilesystem(ContributedPackage pack, File installationFolder, String architecture, String version) { + ContributedPlatform platform = pack.findPlatform(architecture, version); + if (platform != null) { + platform.setInstalled(true); + platform.setReadOnly(false); + platform.setInstalledFolder(installationFolder); + } + return platform; + } + + @Override + public String toString() { + return index.toString(); + } + + public List createTargetPackages() throws TargetPlatformException { + List packages = new ArrayList(); + + if (index == null) { + return packages; + } + + for (ContributedPackage aPackage : index.getPackages()) { + ContributedTargetPackage targetPackage = new ContributedTargetPackage(aPackage.getName()); + + List platforms = new LinkedList(Collections2.filter(aPackage.getPlatforms(), new InstalledPredicate())); + Collections.sort(platforms, new DownloadableContributionBuiltInAtTheBottomComparator()); + + for (ContributedPlatform platform : platforms) { + String arch = platform.getArchitecture(); + File folder = platform.getInstalledFolder(); + + TargetPlatform targetPlatform = new ContributedTargetPlatform(arch, folder, targetPackage, index); + if (!targetPackage.hasPlatform(targetPlatform)) { + targetPackage.addPlatform(targetPlatform); + } + } + + if (targetPackage.hasPlatforms()) { + packages.add(targetPackage); + } + } + return packages; + } + + /** + * Check if a ContributedTool is currently in use by an installed platform + * + * @param tool + * @return + */ + public boolean isContributedToolUsed(ContributedTool tool) { + for (ContributedPackage pack : index.getPackages()) { + for (ContributedPlatform platform : pack.getPlatforms()) { + if (!platform.isInstalled()) + continue; + for (ContributedTool requiredTool : platform.getResolvedTools()) { + if (requiredTool.equals(tool)) + return true; + } + } + } + return false; + } + + public Set getInstalledTools() { + Set tools = new HashSet(); + if (index == null) { + return tools; + } + for (ContributedPackage pack : index.getPackages()) { + Collection platforms = Collections2.filter(pack.getPlatforms(), new InstalledPredicate()); + ImmutableListMultimap platformsByName = Multimaps.index(platforms, new Function() { + @Override + public String apply(ContributedPlatform contributedPlatform) { + return contributedPlatform.getName(); + } + }); + + for (Map.Entry> entry : platformsByName.asMap().entrySet()) { + Collection platformsWithName = entry.getValue(); + if (platformsWithName.size() > 1) { + platformsWithName = Collections2.filter(platformsWithName, Predicates.not(new BuiltInPredicate())); + } + for (ContributedPlatform platform : platformsWithName) { + tools.addAll(platform.getResolvedTools()); + } + } + } + return tools; + } + + public ContributionsIndex getIndex() { + return index; + } + + public File getPackagesFolder() { + return packagesFolder; + } + + public File getStagingFolder() { + return stagingFolder; + } + + public File getIndexFile(String name) { + return new File(preferencesFolder, name); + } + + public List getPackages() { + if (index == null) { + return new LinkedList(); + } + return index.getPackages(); + } + + public List getCategories() { + if (index == null) { + return new LinkedList(); + } + return index.getCategories(); + } + + public ContributedPlatform getInstalled(String packageName, String platformArch) { + if (index == null) { + return null; + } + return index.getInstalled(packageName, platformArch); + } +} diff --git a/arduino-core/src/cc/arduino/contributions/packages/DownloadableContribution.java b/arduino-core/src/cc/arduino/contributions/packages/DownloadableContribution.java new file mode 100644 index 000000000..5152eac71 --- /dev/null +++ b/arduino-core/src/cc/arduino/contributions/packages/DownloadableContribution.java @@ -0,0 +1,112 @@ +/* + * This file is part of Arduino. + * + * Copyright 2014 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ +package cc.arduino.contributions.packages; + +import cc.arduino.contributions.VersionHelper; +import com.github.zafarkhaja.semver.Version; + +import java.io.File; + +public abstract class DownloadableContribution { + + private boolean installed; + private File installedFolder; + + private boolean downloaded; + private File downloadedFile; + + public abstract String getUrl(); + + public abstract String getVersion(); + + public abstract String getChecksum(); + + public abstract long getSize(); + + public abstract String getArchiveFileName(); + + public boolean isDownloaded() { + return downloaded; + } + + public void setDownloaded(boolean downloaded) { + this.downloaded = downloaded; + } + + public File getDownloadedFile() { + return downloadedFile; + } + + public void setDownloadedFile(File downloadedFile) { + this.downloadedFile = downloadedFile; + } + + public boolean isInstalled() { + return installed; + } + + public void setInstalled(boolean installed) { + this.installed = installed; + } + + public File getInstalledFolder() { + return installedFolder; + } + + public void setInstalledFolder(File installedFolder) { + this.installedFolder = installedFolder; + } + + private boolean readOnly; + + public boolean isReadOnly() { + return readOnly; + } + + public void setReadOnly(boolean readOnly) { + this.readOnly = readOnly; + } + + public String getParsedVersion() { + Version version = VersionHelper.valueOf(getVersion()); + if (version == null) { + return null; + } + return version.toString(); + } + + @Override + public String toString() { + String res = ""; + if (installed) { + res += "installed on " + installedFolder.getAbsolutePath() + " (" + getSize() + " bytes)"; + } + return res; + } +} diff --git a/arduino-core/src/cc/arduino/contributions/packages/DownloadableContributionsDownloader.java b/arduino-core/src/cc/arduino/contributions/packages/DownloadableContributionsDownloader.java new file mode 100644 index 000000000..a3ac4d9ec --- /dev/null +++ b/arduino-core/src/cc/arduino/contributions/packages/DownloadableContributionsDownloader.java @@ -0,0 +1,107 @@ +/* + * This file is part of Arduino. + * + * Copyright 2014 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ +package cc.arduino.contributions.packages; + +import cc.arduino.utils.FileHash; +import cc.arduino.utils.Progress; +import cc.arduino.utils.network.FileDownloader; + +import java.io.File; +import java.net.URL; +import java.util.Observable; +import java.util.Observer; + +import static processing.app.I18n._; +import static processing.app.I18n.format; + +public class DownloadableContributionsDownloader { + + private final File stagingFolder; + + public DownloadableContributionsDownloader(File _stagingFolder) { + stagingFolder = _stagingFolder; + } + + public File download(DownloadableContribution contribution, + final Progress progress, final String statusText) + throws Exception { + URL url = new URL(contribution.getUrl()); + final File outputFile = new File(stagingFolder, contribution.getArchiveFileName()); + + // Ensure the existence of staging folder + stagingFolder.mkdirs(); + + // Need to download or resume downloading? + if (!outputFile.isFile() || (outputFile.length() < contribution.getSize())) { + download(url, outputFile, progress, statusText); + } + + // Test checksum + progress.setStatus(_("Verifying archive integrity...")); + onProgress(progress); + String checksum = contribution.getChecksum(); + String algo = checksum.split(":")[0]; + if (!FileHash.hash(outputFile, algo).equalsIgnoreCase(checksum)) { + throw new Exception(_("CRC doesn't match. File is corrupted.")); + } + + contribution.setDownloaded(true); + contribution.setDownloadedFile(outputFile); + return outputFile; + } + + public void download(URL url, File tmpFile, final Progress progress, + final String statusText) throws Exception { + FileDownloader downloader = new FileDownloader(url, tmpFile); + downloader.addObserver(new Observer() { + @Override + public void update(Observable o, Object arg) { + FileDownloader me = (FileDownloader) o; + String msg = ""; + if (me.getDownloadSize() != null) { + long downloaded = (me.getInitialSize() + me.getDownloaded()) / 1000; + long total = (me.getInitialSize() + me.getDownloadSize()) / 1000; + msg = format(_("Downloaded {0}kb of {1}kb."), downloaded, total); + } + progress.setStatus(statusText + " " + msg); + progress.setProgress(me.getProgress()); + onProgress(progress); + } + }); + downloader.download(); + if (!downloader.isCompleted()) { + throw new Exception(format(_("Error downloading {0}"), url), downloader.getError()); + } + } + + protected void onProgress(Progress progress) { + // Empty + } + +} diff --git a/arduino-core/src/cc/arduino/contributions/packages/HostDependentDownloadableContribution.java b/arduino-core/src/cc/arduino/contributions/packages/HostDependentDownloadableContribution.java new file mode 100644 index 000000000..c9c7ec1b6 --- /dev/null +++ b/arduino-core/src/cc/arduino/contributions/packages/HostDependentDownloadableContribution.java @@ -0,0 +1,72 @@ +/* + * This file is part of Arduino. + * + * Copyright 2014 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ +package cc.arduino.contributions.packages; + +import processing.app.Platform; + +public abstract class HostDependentDownloadableContribution extends DownloadableContribution { + + public abstract String getHost(); + + @Override + public String toString() { + return getHost() + " " + super.toString(); + } + + public boolean isCompatible(Platform platform) { + String osName = platform.getOsName(); + assert osName != null; + String osArch = platform.getOsArch(); + assert osArch != null; + + String host = getHost(); + + if (osName.contains("Linux")) { + if (osArch.contains("amd64")) { + return host.matches("x86_64-.*linux-gnu"); + } else { + return host.matches("i[3456]86-.*linux-gnu"); + } + } + + if (osName.contains("Windows")) { + return host.matches("i[3456]86-.*mingw32") || host.matches("i[3456]86-.*cygwin"); + } + + if (osName.contains("Mac")) { + if (osArch.contains("x86_64")) { + return host.matches("x86_64-apple-darwin.*") || host.matches("i[3456]86-apple-darwin.*"); + } else { + return host.matches("i[3456]86-apple-darwin.*"); + } + } + + return false; + } +} diff --git a/arduino-core/src/cc/arduino/contributions/packages/PackageIndexFilenameFilter.java b/arduino-core/src/cc/arduino/contributions/packages/PackageIndexFilenameFilter.java new file mode 100644 index 000000000..61e7c2663 --- /dev/null +++ b/arduino-core/src/cc/arduino/contributions/packages/PackageIndexFilenameFilter.java @@ -0,0 +1,18 @@ +package cc.arduino.contributions.packages; + +import java.io.File; +import java.io.FilenameFilter; + +public class PackageIndexFilenameFilter implements FilenameFilter { + + private final String defaultPackageIndexFileName; + + public PackageIndexFilenameFilter(String defaultPackageIndexFileName) { + this.defaultPackageIndexFileName = defaultPackageIndexFileName; + } + + @Override + public boolean accept(File file, String name) { + return new File(file, name).isFile() && !defaultPackageIndexFileName.equals(name) && name.startsWith("package_") && name.endsWith("_index.json"); + } +} diff --git a/arduino-core/src/cc/arduino/contributions/packages/TestPackageIndexFilenameFilter.java b/arduino-core/src/cc/arduino/contributions/packages/TestPackageIndexFilenameFilter.java new file mode 100644 index 000000000..6d134eb77 --- /dev/null +++ b/arduino-core/src/cc/arduino/contributions/packages/TestPackageIndexFilenameFilter.java @@ -0,0 +1,27 @@ +package cc.arduino.contributions.packages; + +import java.io.File; +import java.io.FilenameFilter; + +public class TestPackageIndexFilenameFilter implements FilenameFilter { + + private final FilenameFilter parent; + + public TestPackageIndexFilenameFilter(FilenameFilter parent) { + this.parent = parent; + } + + public TestPackageIndexFilenameFilter() { + this(null); + } + + @Override + public boolean accept(File file, String name) { + boolean result = false; + if (parent != null) { + result = parent.accept(file, name); + } + result = result || (new File(file, name).isFile() && name.startsWith("test_package_") && name.endsWith("_index.json")); + return result; + } +} diff --git a/arduino-core/src/cc/arduino/contributions/packages/filters/PlatformArchitecturePredicate.java b/arduino-core/src/cc/arduino/contributions/packages/filters/PlatformArchitecturePredicate.java new file mode 100644 index 000000000..2f7957dfd --- /dev/null +++ b/arduino-core/src/cc/arduino/contributions/packages/filters/PlatformArchitecturePredicate.java @@ -0,0 +1,48 @@ +/* + * This file is part of Arduino. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ + +package cc.arduino.contributions.packages.filters; + +import cc.arduino.contributions.packages.ContributedPlatform; +import com.google.common.base.Predicate; + +public class PlatformArchitecturePredicate implements Predicate { + + private final String platformArch; + + public PlatformArchitecturePredicate(String platformArch) { + this.platformArch = platformArch; + } + + @Override + public boolean apply(ContributedPlatform contributedPlatform) { + return platformArch.equals(contributedPlatform.getArchitecture()); + } + +} diff --git a/arduino-core/src/cc/arduino/files/DeleteFilesOnShutdown.java b/arduino-core/src/cc/arduino/files/DeleteFilesOnShutdown.java new file mode 100644 index 000000000..7d9f60139 --- /dev/null +++ b/arduino-core/src/cc/arduino/files/DeleteFilesOnShutdown.java @@ -0,0 +1,47 @@ +package cc.arduino.files; + +import processing.app.PreferencesData; +import processing.app.helpers.FileUtils; + +import java.io.File; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +public class DeleteFilesOnShutdown implements Runnable { + + public static final DeleteFilesOnShutdown INSTANCE = new DeleteFilesOnShutdown(); + + public static void add(File file) { + INSTANCE.addFile(file); + } + + private final List files; + + public DeleteFilesOnShutdown() { + this.files = new LinkedList(); + } + + public synchronized void addFile(File file) { + this.files.add(file); + } + + @Override + public void run() { + boolean preserveTempFiles = PreferencesData.getBoolean("runtime.preserve.temp.files"); + if (preserveTempFiles) { + return; + } + List copyOfFiles; + synchronized (this) { + copyOfFiles = new LinkedList(files); + } + Collections.reverse(copyOfFiles); + for (File file : copyOfFiles) { + if (file.exists() && file.canWrite()) { + FileUtils.recursiveDelete(file); + } + } + } + +} diff --git a/arduino-core/src/cc/arduino/filters/FileExecutablePredicate.java b/arduino-core/src/cc/arduino/filters/FileExecutablePredicate.java new file mode 100644 index 000000000..251536086 --- /dev/null +++ b/arduino-core/src/cc/arduino/filters/FileExecutablePredicate.java @@ -0,0 +1,43 @@ +/* + * This file is part of Arduino. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ + +package cc.arduino.filters; + +import com.google.common.base.Predicate; + +import java.io.File; + +public class FileExecutablePredicate implements Predicate { + + @Override + public boolean apply(File file) { + return file.isFile() && file.exists() && file.canRead() && file.canExecute(); + } + +} diff --git a/arduino-core/src/cc/arduino/packages/Discovery.java b/arduino-core/src/cc/arduino/packages/Discovery.java index 633c1fcc7..eb4b41da2 100644 --- a/arduino-core/src/cc/arduino/packages/Discovery.java +++ b/arduino-core/src/cc/arduino/packages/Discovery.java @@ -29,36 +29,27 @@ package cc.arduino.packages; -import processing.app.helpers.PreferencesMap; - import java.util.List; public interface Discovery { - /** - * Set discovery preferences - * - * @param options - */ - public void setPreferences(PreferencesMap options); - /** * Start discovery service * * @throws Exception */ - public void start() throws Exception; + void start() throws Exception; /** * Stop discovery service */ - public void stop() throws Exception; + void stop() throws Exception; /** * Return the list of discovered ports. * * @return */ - public List discovery(); + List listDiscoveredBoards(); } diff --git a/arduino-core/src/cc/arduino/packages/DiscoveryManager.java b/arduino-core/src/cc/arduino/packages/DiscoveryManager.java index 5c45314a1..ddb774b94 100644 --- a/arduino-core/src/cc/arduino/packages/DiscoveryManager.java +++ b/arduino-core/src/cc/arduino/packages/DiscoveryManager.java @@ -63,7 +63,7 @@ public class DiscoveryManager { try { d.stop(); } catch (Exception e) { - e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. + e.printStackTrace(); //just printing as the JVM is terminating } } } @@ -74,7 +74,7 @@ public class DiscoveryManager { public List discovery() { List res = new ArrayList(); for (Discovery d : discoverers) { - res.addAll(d.discovery()); + res.addAll(d.listDiscoveredBoards()); } return res; } diff --git a/arduino-core/src/cc/arduino/packages/UploaderFactory.java b/arduino-core/src/cc/arduino/packages/UploaderFactory.java index 8cfe44d9e..56828a753 100644 --- a/arduino-core/src/cc/arduino/packages/UploaderFactory.java +++ b/arduino-core/src/cc/arduino/packages/UploaderFactory.java @@ -36,8 +36,9 @@ import processing.app.debug.TargetBoard; public class UploaderFactory { public Uploader newUploader(TargetBoard board, BoardPort port, boolean noUploadPort) { - if (noUploadPort) - return new SerialUploader(noUploadPort); + if (noUploadPort) { + return new SerialUploader(true); + } if ("true".equals(board.getPreferences().get("upload.via_ssh")) && port != null && "network".equals(port.getProtocol())) { return new SSHUploader(port); diff --git a/arduino-core/src/cc/arduino/packages/discoverers/NetworkDiscovery.java b/arduino-core/src/cc/arduino/packages/discoverers/NetworkDiscovery.java index 6f593571a..b7ede72c2 100644 --- a/arduino-core/src/cc/arduino/packages/discoverers/NetworkDiscovery.java +++ b/arduino-core/src/cc/arduino/packages/discoverers/NetworkDiscovery.java @@ -31,9 +31,9 @@ package cc.arduino.packages.discoverers; import cc.arduino.packages.BoardPort; import cc.arduino.packages.Discovery; +import cc.arduino.packages.discoverers.network.BoardReachabilityFilter; import cc.arduino.packages.discoverers.network.NetworkChecker; import processing.app.BaseNoGui; -import processing.app.helpers.NetUtils; import processing.app.helpers.PreferencesMap; import processing.app.zeroconf.jmdns.ArduinoDNSTaskStarter; @@ -41,70 +41,57 @@ import javax.jmdns.*; import javax.jmdns.impl.DNSTaskStarter; import java.io.IOException; import java.net.InetAddress; -import java.net.UnknownHostException; import java.util.*; public class NetworkDiscovery implements Discovery, ServiceListener, cc.arduino.packages.discoverers.network.NetworkTopologyListener { - private Timer timer; - private final List ports; + private static final int MAX_TIME_AWAITING_FOR_PACKAGES = 5000; + + private final List boardPortsDiscoveredWithJmDNS; private final Map mappedJmDNSs; + private Timer networkCheckerTimer; + private Timer boardReachabilityFilterTimer; + private final List reachableBoardPorts; public NetworkDiscovery() { DNSTaskStarter.Factory.setClassDelegate(new ArduinoDNSTaskStarter()); - this.ports = new ArrayList(); + this.boardPortsDiscoveredWithJmDNS = new LinkedList(); this.mappedJmDNSs = new Hashtable(); + this.reachableBoardPorts = new LinkedList(); } @Override - public List discovery() { - List boardPorts = clonePortsList(); - Iterator boardPortIterator = boardPorts.iterator(); - while (boardPortIterator.hasNext()) { - try { - BoardPort board = boardPortIterator.next(); - - InetAddress inetAddress = InetAddress.getByName(board.getAddress()); - int broadcastedPort = Integer.valueOf(board.getPrefs().get("port")); - - List ports = new LinkedList(); - ports.add(broadcastedPort); - - //dirty code: allows non up to date yuns to be discovered. Newer yuns will broadcast port 22 - if (broadcastedPort == 80) { - ports.add(0, 22); - } - - boolean reachable = NetUtils.isReachable(inetAddress, ports); - if (!reachable) { - boardPortIterator.remove(); - } - } catch (UnknownHostException e) { - boardPortIterator.remove(); - } - } - return boardPorts; - } - - private List clonePortsList() { - synchronized (this) { - return new ArrayList(this.ports); + public List listDiscoveredBoards() { + synchronized (reachableBoardPorts) { + return new LinkedList(reachableBoardPorts); } } - @Override - public void setPreferences(PreferencesMap options) { + public void setReachableBoardPorts(List newReachableBoardPorts) { + synchronized (reachableBoardPorts) { + this.reachableBoardPorts.clear(); + this.reachableBoardPorts.addAll(newReachableBoardPorts); + } + } + + public List getBoardPortsDiscoveredWithJmDNS() { + synchronized (boardPortsDiscoveredWithJmDNS) { + return new LinkedList(boardPortsDiscoveredWithJmDNS); + } } @Override public void start() throws IOException { - this.timer = new Timer(this.getClass().getName() + " timer"); - new NetworkChecker(this, NetworkTopologyDiscovery.Factory.getInstance()).start(timer); + this.networkCheckerTimer = new Timer(NetworkChecker.class.getName()); + new NetworkChecker(this, NetworkTopologyDiscovery.Factory.getInstance()).start(networkCheckerTimer); + this.boardReachabilityFilterTimer = new Timer(BoardReachabilityFilter.class.getName()); + new BoardReachabilityFilter(this).start(boardReachabilityFilterTimer); } @Override public void stop() throws IOException { - timer.purge(); + this.networkCheckerTimer.purge(); + this.boardReachabilityFilterTimer.purge(); // we don't close each JmDNS instance as it's too slow } @@ -125,16 +112,27 @@ public class NetworkDiscovery implements Discovery, ServiceListener, cc.arduino. @Override public void serviceRemoved(ServiceEvent serviceEvent) { String name = serviceEvent.getName(); - synchronized (this) { - for (BoardPort port : ports) { - if (port.getBoardName().equals(name)) - ports.remove(port); + synchronized (boardPortsDiscoveredWithJmDNS) { + for (BoardPort port : boardPortsDiscoveredWithJmDNS) { + if (port.getBoardName().equals(name)) { + boardPortsDiscoveredWithJmDNS.remove(port); + } } } } @Override public void serviceResolved(ServiceEvent serviceEvent) { + int sleptFor = 0; + while (BaseNoGui.packages == null && sleptFor <= MAX_TIME_AWAITING_FOR_PACKAGES) { + try { + Thread.sleep(1000); + sleptFor += 1000; + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + ServiceInfo info = serviceEvent.getInfo(); for (InetAddress inetAddress : info.getInet4Addresses()) { String address = inetAddress.getHostAddress(); @@ -147,12 +145,11 @@ public class NetworkDiscovery implements Discovery, ServiceListener, cc.arduino. board = info.getPropertyString("board"); prefs.put("board", board); prefs.put("distro_version", info.getPropertyString("distro_version")); + prefs.put("port", "" + info.getPort()); } - prefs.put("port", "" + info.getPort()); - String label = name + " at " + address; - if (board != null) { + if (board != null && BaseNoGui.packages != null) { String boardName = BaseNoGui.getPlatform().resolveDeviceByBoardID(BaseNoGui.packages, board); if (boardName != null) { label += " (" + boardName + ")"; @@ -166,19 +163,21 @@ public class NetworkDiscovery implements Discovery, ServiceListener, cc.arduino. port.setPrefs(prefs); port.setLabel(label); - synchronized (this) { + synchronized (boardPortsDiscoveredWithJmDNS) { removeDuplicateBoards(port); - ports.add(port); + boardPortsDiscoveredWithJmDNS.add(port); } } } private void removeDuplicateBoards(BoardPort newBoard) { - Iterator iterator = ports.iterator(); - while (iterator.hasNext()) { - BoardPort board = iterator.next(); - if (newBoard.getAddress().equals(board.getAddress())) { - iterator.remove(); + synchronized (boardPortsDiscoveredWithJmDNS) { + Iterator iterator = boardPortsDiscoveredWithJmDNS.iterator(); + while (iterator.hasNext()) { + BoardPort board = iterator.next(); + if (newBoard.getAddress().equals(board.getAddress())) { + iterator.remove(); + } } } } diff --git a/arduino-core/src/cc/arduino/packages/discoverers/SerialDiscovery.java b/arduino-core/src/cc/arduino/packages/discoverers/SerialDiscovery.java index 6c9cc8450..354e88da3 100644 --- a/arduino-core/src/cc/arduino/packages/discoverers/SerialDiscovery.java +++ b/arduino-core/src/cc/arduino/packages/discoverers/SerialDiscovery.java @@ -31,86 +31,49 @@ package cc.arduino.packages.discoverers; import cc.arduino.packages.BoardPort; import cc.arduino.packages.Discovery; -import processing.app.BaseNoGui; -import processing.app.Platform; -import processing.app.Serial; -import processing.app.debug.TargetBoard; -import processing.app.helpers.PreferencesMap; +import cc.arduino.packages.discoverers.serial.SerialBoardsLister; -import java.util.ArrayList; -import java.util.HashMap; +import java.util.LinkedList; import java.util.List; -import java.util.Map; +import java.util.Timer; import static processing.app.I18n._; public class SerialDiscovery implements Discovery { - static { - //makes transifex happy - _("Uncertified"); + private Timer serialBoardsListerTimer; + private final List serialBoardPorts; + + public SerialDiscovery() { + this.serialBoardPorts = new LinkedList(); } @Override - public List discovery() { - Platform os = BaseNoGui.getPlatform(); - String devicesListOutput = os.preListAllCandidateDevices(); + public List listDiscoveredBoards() { + return getSerialBoardPorts(); + } - List res = new ArrayList(); - - List ports = Serial.list(); - - for (String port : ports) { - Map boardData = os.resolveDeviceAttachedTo(port, BaseNoGui.packages, devicesListOutput); - - BoardPort boardPort = new BoardPort(); - boardPort.setAddress(port); - boardPort.setProtocol("serial"); - - String label = port; - - PreferencesMap prefs = new PreferencesMap(); - - if (boardData != null) { - prefs.put("vid", boardData.get("vid").toString()); - prefs.put("pid", boardData.get("pid").toString()); - - TargetBoard board = (TargetBoard) boardData.get("board"); - if (board != null) { - String warningKey = "vid." + boardData.get("vid").toString() + ".warning"; - String warning = board.getPreferences().get(warningKey); - prefs.put("warning", warning); - - String boardName = board.getName(); - if (boardName != null) { - if (warning != null) { - label += " (" + boardName + " - " + _(warning) + ")"; - } else { - label += " (" + boardName + ")"; - } - } - boardPort.setBoardName(boardName); - } - } - - boardPort.setLabel(label); - boardPort.setPrefs(prefs); - - res.add(boardPort); + public List getSerialBoardPorts() { + synchronized (serialBoardPorts) { + return new LinkedList(serialBoardPorts); } - return res; } - @Override - public void setPreferences(PreferencesMap options) { + public void setSerialBoardPorts(List newSerialBoardPorts) { + synchronized (serialBoardPorts) { + serialBoardPorts.clear(); + serialBoardPorts.addAll(newSerialBoardPorts); + } } @Override public void start() { + this.serialBoardsListerTimer = new Timer(SerialBoardsLister.class.getName()); + new SerialBoardsLister(this).start(serialBoardsListerTimer); } @Override public void stop() { + this.serialBoardsListerTimer.purge(); } - } diff --git a/arduino-core/src/cc/arduino/packages/discoverers/network/BoardReachabilityFilter.java b/arduino-core/src/cc/arduino/packages/discoverers/network/BoardReachabilityFilter.java new file mode 100644 index 000000000..fbc3e0813 --- /dev/null +++ b/arduino-core/src/cc/arduino/packages/discoverers/network/BoardReachabilityFilter.java @@ -0,0 +1,83 @@ +/* + * This file is part of Arduino. + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + */ + +package cc.arduino.packages.discoverers.network; + +import cc.arduino.packages.BoardPort; +import cc.arduino.packages.discoverers.NetworkDiscovery; +import processing.app.helpers.NetUtils; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.*; + +public class BoardReachabilityFilter extends TimerTask { + + private final NetworkDiscovery networkDiscovery; + + public BoardReachabilityFilter(NetworkDiscovery networkDiscovery) { + this.networkDiscovery = networkDiscovery; + } + + public void start(Timer timer) { + timer.schedule(this, 0, 3000); + } + + @Override + public void run() { + List boardPorts = networkDiscovery.getBoardPortsDiscoveredWithJmDNS(); + + Iterator boardPortIterator = boardPorts.iterator(); + while (boardPortIterator.hasNext()) { + try { + BoardPort board = boardPortIterator.next(); + + InetAddress inetAddress = InetAddress.getByName(board.getAddress()); + int broadcastedPort = Integer.valueOf(board.getPrefs().get("port")); + + List ports = new LinkedList(); + ports.add(broadcastedPort); + + //dirty code: allows non up to date yuns to be discovered. Newer yuns will broadcast port 22 + if (broadcastedPort == 80) { + ports.add(0, 22); + } + + boolean reachable = NetUtils.isReachable(inetAddress, ports); + if (!reachable) { + boardPortIterator.remove(); + } + } catch (UnknownHostException e) { + boardPortIterator.remove(); + } + } + + networkDiscovery.setReachableBoardPorts(boardPorts); + } +} diff --git a/arduino-core/src/cc/arduino/packages/discoverers/serial/SerialBoardsLister.java b/arduino-core/src/cc/arduino/packages/discoverers/serial/SerialBoardsLister.java new file mode 100644 index 000000000..58ad2e509 --- /dev/null +++ b/arduino-core/src/cc/arduino/packages/discoverers/serial/SerialBoardsLister.java @@ -0,0 +1,115 @@ +/* + * This file is part of Arduino. + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + */ + +package cc.arduino.packages.discoverers.serial; + +import cc.arduino.packages.BoardPort; +import cc.arduino.packages.discoverers.SerialDiscovery; +import processing.app.BaseNoGui; +import processing.app.Platform; +import processing.app.Serial; +import processing.app.debug.TargetBoard; +import processing.app.helpers.PreferencesMap; + +import java.util.*; + +public class SerialBoardsLister extends TimerTask { + + private static final int MAX_TIME_AWAITING_FOR_PACKAGES = 5000; + + private final SerialDiscovery serialDiscovery; + + public SerialBoardsLister(SerialDiscovery serialDiscovery) { + this.serialDiscovery = serialDiscovery; + } + + public void start(Timer timer) { + timer.schedule(this, 0, 3000); + } + + @Override + public void run() { + int sleptFor = 0; + while (BaseNoGui.packages == null && sleptFor <= MAX_TIME_AWAITING_FOR_PACKAGES) { + try { + Thread.sleep(1000); + sleptFor += 1000; + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + Platform platform = BaseNoGui.getPlatform(); + if (platform == null) { + return; + } + + List boardPorts = new LinkedList(); + + List ports = Serial.list(); + + String devicesListOutput = null; + if (!ports.isEmpty()) { + devicesListOutput = platform.preListAllCandidateDevices(); + } + + for (String port : ports) { + Map boardData = platform.resolveDeviceAttachedTo(port, BaseNoGui.packages, devicesListOutput); + + BoardPort boardPort = new BoardPort(); + boardPort.setAddress(port); + boardPort.setProtocol("serial"); + + String label = port; + + PreferencesMap prefs = new PreferencesMap(); + + if (boardData != null) { + prefs.put("vid", boardData.get("vid").toString()); + prefs.put("pid", boardData.get("pid").toString()); + + TargetBoard board = (TargetBoard) boardData.get("board"); + if (board != null) { + String boardName = board.getName(); + if (boardName != null) { + label += " (" + boardName + ")"; + } + boardPort.setBoardName(boardName); + } + } + + boardPort.setLabel(label); + boardPort.setPrefs(prefs); + + boardPorts.add(boardPort); + } + + serialDiscovery.setSerialBoardPorts(boardPorts); + } +} diff --git a/arduino-core/src/cc/arduino/packages/uploaders/SSHUploader.java b/arduino-core/src/cc/arduino/packages/uploaders/SSHUploader.java index b99c00a5c..cadb05736 100644 --- a/arduino-core/src/cc/arduino/packages/uploaders/SSHUploader.java +++ b/arduino-core/src/cc/arduino/packages/uploaders/SSHUploader.java @@ -119,7 +119,10 @@ public class SSHUploader extends Uploader { private boolean runAVRDude(SSH ssh) throws IOException, JSchException { TargetPlatform targetPlatform = BaseNoGui.getTargetPlatform(); PreferencesMap prefs = PreferencesData.getMap(); - prefs.putAll(BaseNoGui.getBoardPreferences()); + PreferencesMap boardPreferences = BaseNoGui.getBoardPreferences(); + if (boardPreferences != null) { + prefs.putAll(boardPreferences); + } prefs.putAll(targetPlatform.getTool(prefs.get("upload.tool"))); String additionalParams = verbose ? prefs.get("upload.params.verbose") : prefs.get("upload.params.quiet"); diff --git a/arduino-core/src/cc/arduino/packages/uploaders/SerialUploader.java b/arduino-core/src/cc/arduino/packages/uploaders/SerialUploader.java index 81c084054..c98d3eab7 100644 --- a/arduino-core/src/cc/arduino/packages/uploaders/SerialUploader.java +++ b/arduino-core/src/cc/arduino/packages/uploaders/SerialUploader.java @@ -60,7 +60,10 @@ public class SerialUploader extends Uploader { // FIXME: Preferences should be reorganized TargetPlatform targetPlatform = BaseNoGui.getTargetPlatform(); PreferencesMap prefs = PreferencesData.getMap(); - prefs.putAll(BaseNoGui.getBoardPreferences()); + PreferencesMap boardPreferences = BaseNoGui.getBoardPreferences(); + if (boardPreferences != null) { + prefs.putAll(boardPreferences); + } String tool = prefs.getOrExcept("upload.tool"); if (tool.contains(":")) { String[] split = tool.split(":", 2); @@ -116,7 +119,7 @@ public class SerialUploader extends Uploader { if (verbose) System.out.println( I18n.format(_("Forcing reset using 1200bps open/close on port {0}"), uploadPort)); - Serial.touchPort(uploadPort, 1200); + Serial.touchForCDCReset(uploadPort); } Thread.sleep(400); if (waitForUploadPort) { @@ -242,13 +245,16 @@ public class SerialUploader extends Uploader { } PreferencesMap prefs = PreferencesData.getMap(); - prefs.putAll(BaseNoGui.getBoardPreferences()); + PreferencesMap boardPreferences = BaseNoGui.getBoardPreferences(); + if (boardPreferences != null) { + prefs.putAll(boardPreferences); + } PreferencesMap programmerPrefs = targetPlatform.getProgrammer(programmer); if (programmerPrefs == null) throw new RunnerException( _("Please select a programmer from Tools->Programmer menu")); + prefs.putAll(targetPlatform.getTool(programmerPrefs.getOrExcept("program.tool"))); prefs.putAll(programmerPrefs); - prefs.putAll(targetPlatform.getTool(prefs.getOrExcept("program.tool"))); prefs.put("build.path", buildPath); prefs.put("build.project_name", className); @@ -295,7 +301,10 @@ public class SerialUploader extends Uploader { // Build configuration for the current programmer PreferencesMap prefs = PreferencesData.getMap(); - prefs.putAll(BaseNoGui.getBoardPreferences()); + PreferencesMap boardPreferences = BaseNoGui.getBoardPreferences(); + if (boardPreferences != null) { + prefs.putAll(boardPreferences); + } prefs.putAll(programmerPrefs); // Create configuration for bootloader tool diff --git a/arduino-core/src/cc/arduino/utils/ArchiveExtractor.java b/arduino-core/src/cc/arduino/utils/ArchiveExtractor.java new file mode 100644 index 000000000..fe68fa870 --- /dev/null +++ b/arduino-core/src/cc/arduino/utils/ArchiveExtractor.java @@ -0,0 +1,303 @@ +/* + * This file is part of Arduino. + * + * Copyright 2014 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ +package cc.arduino.utils; + +import org.apache.commons.compress.archivers.ArchiveEntry; +import org.apache.commons.compress.archivers.ArchiveInputStream; +import org.apache.commons.compress.archivers.tar.TarArchiveEntry; +import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; +import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream; +import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream; +import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream; +import processing.app.I18n; +import processing.app.Platform; + +import java.io.*; +import java.util.HashMap; +import java.util.Map; + +import static processing.app.I18n._; + +public class ArchiveExtractor { + + private final Platform platform; + + public ArchiveExtractor(Platform platform) { + assert platform != null; + this.platform = platform; + } + + /** + * Extract source into destFolder. source file archive + * format is autodetected from file extension. + * + * @param archiveFile + * @param destFolder + * @throws IOException + */ + public void extract(File archiveFile, File destFolder) throws IOException, InterruptedException { + extract(archiveFile, destFolder, 0); + } + + /** + * Extract source into destFolder. source file archive + * format is autodetected from file extension. + * + * @param archiveFile Archive file to extract + * @param destFolder Destination folder + * @param stripPath Number of path elements to strip from the paths contained in the + * archived files + * @throws IOException + */ + public void extract(File archiveFile, File destFolder, int stripPath) throws IOException, InterruptedException { + extract(archiveFile, destFolder, stripPath, false); + } + + + public void extract(File archiveFile, File destFolder, int stripPath, boolean overwrite) throws IOException, InterruptedException { + + // Folders timestamps must be set at the end of archive extraction + // (because creating a file in a folder alters the folder's timestamp) + Map foldersTimestamps = new HashMap(); + + ArchiveInputStream in = null; + try { + + // Create an ArchiveInputStream with the correct archiving algorithm + if (archiveFile.getName().endsWith("tar.bz2")) { + in = new TarArchiveInputStream(new BZip2CompressorInputStream(new FileInputStream(archiveFile))); + } else if (archiveFile.getName().endsWith("zip")) { + in = new ZipArchiveInputStream(new FileInputStream(archiveFile)); + } else if (archiveFile.getName().endsWith("tar.gz")) { + in = new TarArchiveInputStream(new GzipCompressorInputStream(new FileInputStream(archiveFile))); + } else if (archiveFile.getName().endsWith("tar")) { + in = new TarArchiveInputStream(new FileInputStream(archiveFile)); + } else { + throw new IOException("Archive format not supported."); + } + + String pathPrefix = ""; + + Map hardLinks = new HashMap(); + Map hardLinksMode = new HashMap(); + Map symLinks = new HashMap(); + Map symLinksModifiedTimes = new HashMap(); + + // Cycle through all the archive entries + while (true) { + ArchiveEntry entry = in.getNextEntry(); + if (entry == null) { + break; + } + + // Extract entry info + long size = entry.getSize(); + String name = entry.getName(); + boolean isDirectory = entry.isDirectory(); + boolean isLink = false; + boolean isSymLink = false; + String linkName = null; + Integer mode = null; + long modifiedTime = entry.getLastModifiedDate().getTime(); + + { + // Skip MacOSX metadata + // http://superuser.com/questions/61185/why-do-i-get-files-like-foo-in-my-tarball-on-os-x + int slash = name.lastIndexOf('/'); + if (slash == -1) { + if (name.startsWith("._")) { + continue; + } + } else { + if (name.substring(slash + 1).startsWith("._")) { + continue; + } + } + } + + // Skip git metadata + // http://www.unix.com/unix-for-dummies-questions-and-answers/124958-file-pax_global_header-means-what.html + if (name.contains("pax_global_header")) { + continue; + } + + if (entry instanceof TarArchiveEntry) { + TarArchiveEntry tarEntry = (TarArchiveEntry) entry; + mode = tarEntry.getMode(); + isLink = tarEntry.isLink(); + isSymLink = tarEntry.isSymbolicLink(); + linkName = tarEntry.getLinkName(); + } + + // On the first archive entry, if requested, detect the common path + // prefix to be stripped from filenames + if (stripPath > 0 && pathPrefix.isEmpty()) { + int slash = 0; + while (stripPath > 0) { + slash = name.indexOf("/", slash); + if (slash == -1) { + throw new IOException("Invalid archive: it must contains a single root folder"); + } + slash++; + stripPath--; + } + pathPrefix = name.substring(0, slash); + } + + // Strip the common path prefix when requested + if (!name.startsWith(pathPrefix)) { + throw new IOException("Invalid archive: it must contains a single root folder while file " + name + " is outside " + pathPrefix); + } + name = name.substring(pathPrefix.length()); + if (name.isEmpty()) { + continue; + } + File outputFile = new File(destFolder, name); + + File outputLinkedFile = null; + if (isLink) { + if (!linkName.startsWith(pathPrefix)) { + throw new IOException("Invalid archive: it must contains a single root folder while file " + linkName + " is outside " + pathPrefix); + } + linkName = linkName.substring(pathPrefix.length()); + outputLinkedFile = new File(destFolder, linkName); + } + if (isSymLink) { + // Symbolic links are referenced with relative paths + outputLinkedFile = new File(linkName); + if (outputLinkedFile.isAbsolute()) { + System.err.println(I18n.format(_("Warning: file {0} links to an absolute path {1}"), outputFile, outputLinkedFile)); + System.err.println(); + } + } + + // Safety check + if (isDirectory) { + if (outputFile.isFile() && !overwrite) { + throw new IOException("Can't create folder " + outputFile + ", a file with the same name exists!"); + } + } else { + // - isLink + // - isSymLink + // - anything else + if (outputFile.exists() && !overwrite) { + throw new IOException("Can't extract file " + outputFile + ", file already exists!"); + } + } + + // Extract the entry + if (isDirectory) { + if (!outputFile.exists() && !outputFile.mkdirs()) { + throw new IOException("Could not create folder: " + outputFile); + } + foldersTimestamps.put(outputFile, modifiedTime); + } else if (isLink) { + hardLinks.put(outputFile, outputLinkedFile); + hardLinksMode.put(outputFile, mode); + } else if (isSymLink) { + symLinks.put(outputFile, linkName); + symLinksModifiedTimes.put(outputFile, modifiedTime); + } else { + // Create the containing folder if not exists + if (!outputFile.getParentFile().isDirectory()) { + outputFile.getParentFile().mkdirs(); + } + copyStreamToFile(in, size, outputFile); + outputFile.setLastModified(modifiedTime); + } + + // Set file/folder permission + if (mode != null && !isSymLink && outputFile.exists()) { + platform.chmod(outputFile, mode); + } + } + + for (Map.Entry entry : hardLinks.entrySet()) { + if (entry.getKey().exists() && overwrite) { + entry.getKey().delete(); + } + platform.link(entry.getValue(), entry.getKey()); + Integer mode = hardLinksMode.get(entry.getKey()); + if (mode != null) { + platform.chmod(entry.getKey(), mode); + } + } + + for (Map.Entry entry : symLinks.entrySet()) { + if (entry.getKey().exists() && overwrite) { + entry.getKey().delete(); + } + platform.symlink(entry.getValue(), entry.getKey()); + entry.getKey().setLastModified(symLinksModifiedTimes.get(entry.getKey())); + } + + } finally { + if (in != null) { + in.close(); + } + } + + // Set folders timestamps + for (File folder : foldersTimestamps.keySet()) { + folder.setLastModified(foldersTimestamps.get(folder)); + } + } + + private static void copyStreamToFile(InputStream in, long size, File outputFile) throws IOException { + FileOutputStream fos = null; + try { + fos = new FileOutputStream(outputFile); + // if size is not available, copy until EOF... + if (size == -1) { + byte buffer[] = new byte[4096]; + int length; + while ((length = in.read(buffer)) != -1) { + fos.write(buffer, 0, length); + } + return; + } + + // ...else copy just the needed amount of bytes + byte buffer[] = new byte[4096]; + while (size > 0) { + int length = in.read(buffer); + if (length <= 0) { + throw new IOException("Error while extracting file " + outputFile.getAbsolutePath()); + } + fos.write(buffer, 0, length); + size -= length; + } + } finally { + if (fos != null) { + fos.close(); + } + } + } + +} diff --git a/arduino-core/src/cc/arduino/utils/FileHash.java b/arduino-core/src/cc/arduino/utils/FileHash.java new file mode 100644 index 000000000..0ce8afd4c --- /dev/null +++ b/arduino-core/src/cc/arduino/utils/FileHash.java @@ -0,0 +1,76 @@ +/* + * This file is part of Arduino. + * + * Copyright 2014 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ +package cc.arduino.utils; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +public class FileHash { + + /** + * Calculate a message digest of a file using the algorithm specified. The + * result is a string containing the algorithm name followed by ":" and by the + * resulting hash in hex. + * + * @param file + * @param algorithm For example "SHA-256" + * @return The algorithm followed by ":" and the hash, for example:
+ * "SHA-256:ee6796513086080cca078cbb383f543c5e508b647a71c9d6f39b7bca41071883" + * @throws IOException + * @throws NoSuchAlgorithmException + */ + public static String hash(File file, String algorithm) throws IOException, NoSuchAlgorithmException { + FileInputStream in = null; + try { + in = new FileInputStream(file); + byte buff[] = new byte[10240]; + MessageDigest digest = MessageDigest.getInstance(algorithm); + while (in.available() > 0) { + int read = in.read(buff); + digest.update(buff, 0, read); + } + byte[] hash = digest.digest(); + String res = ""; + for (byte b : hash) { + int c = b & 0xFF; + if (c < 0x10) + res += "0"; + res += Integer.toHexString(c); + } + return algorithm + ":" + res; + } finally { + if (in != null) { + in.close(); + } + } + } +} diff --git a/arduino-core/src/cc/arduino/utils/MultiStepProgress.java b/arduino-core/src/cc/arduino/utils/MultiStepProgress.java new file mode 100644 index 000000000..6846ab79a --- /dev/null +++ b/arduino-core/src/cc/arduino/utils/MultiStepProgress.java @@ -0,0 +1,74 @@ +/* + * This file is part of Arduino. + * + * Copyright 2014 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ +package cc.arduino.utils; + +public class MultiStepProgress implements Progress { + + private final double steps; + + private double step; + private double stepProgress; + + String status; + + public MultiStepProgress(int _steps) { + steps = _steps; + step = 0.0; + stepProgress = 0.0; + } + + public double getGlobalProgress() { + return (step + stepProgress) / steps; + } + + public void stepDone() { + step += 100.0; + setProgress(0.0); + } + + @Override + public void setProgress(double progress) { + stepProgress = progress; + } + + @Override + public void setStatus(String _status) { + status = _status; + } + + @Override + public double getProgress() { + return getGlobalProgress(); + } + + @Override + public String getStatus() { + return status; + } +} diff --git a/arduino-core/src/cc/arduino/utils/Progress.java b/arduino-core/src/cc/arduino/utils/Progress.java new file mode 100644 index 000000000..cc63ff3a8 --- /dev/null +++ b/arduino-core/src/cc/arduino/utils/Progress.java @@ -0,0 +1,41 @@ +/* + * This file is part of Arduino. + * + * Copyright 2014 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ +package cc.arduino.utils; + +public interface Progress { + + void setProgress(double progress); + + double getProgress(); + + void setStatus(String _status); + + String getStatus(); + +} diff --git a/arduino-core/src/cc/arduino/utils/ReverseComparator.java b/arduino-core/src/cc/arduino/utils/ReverseComparator.java new file mode 100644 index 000000000..50c0ccd45 --- /dev/null +++ b/arduino-core/src/cc/arduino/utils/ReverseComparator.java @@ -0,0 +1,17 @@ +package cc.arduino.utils; + +import java.util.Comparator; + +public class ReverseComparator implements Comparator { + + private final Comparator orig; + + public ReverseComparator(Comparator orig) { + this.orig = orig; + } + + @Override + public int compare(T t, T t1) { + return -1 * orig.compare(t, t1); + } +} diff --git a/arduino-core/src/cc/arduino/utils/network/FileDownloader.java b/arduino-core/src/cc/arduino/utils/network/FileDownloader.java new file mode 100644 index 000000000..358de9759 --- /dev/null +++ b/arduino-core/src/cc/arduino/utils/network/FileDownloader.java @@ -0,0 +1,255 @@ +/* + * This file is part of Arduino. + * + * Copyright 2014 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ +package cc.arduino.utils.network; + +import org.apache.commons.codec.binary.Base64; +import processing.app.PreferencesData; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.RandomAccessFile; +import java.net.HttpURLConnection; +import java.net.SocketTimeoutException; +import java.net.URL; +import java.util.Observable; + +public class FileDownloader extends Observable { + + public enum Status { + CONNECTING, // + CONNECTION_TIMEOUT_ERROR, // + DOWNLOADING, // + COMPLETE, // + CANCELLED, // + ERROR, // + } + + private Status status; + private long initialSize; + private Long downloadSize = null; + private long downloaded; + private final URL downloadUrl; + + private final File outputFile; + private InputStream stream = null; + private Exception error; + + public FileDownloader(URL url, File file) { + downloadUrl = url; + outputFile = file; + downloaded = 0; + initialSize = 0; + } + + public long getInitialSize() { + return initialSize; + } + + public Long getDownloadSize() { + return downloadSize; + } + + public void setDownloadSize(Long downloadSize) { + this.downloadSize = downloadSize; + setChanged(); + notifyObservers(); + } + + public long getDownloaded() { + return downloaded; + } + + private void setDownloaded(long downloaded) { + this.downloaded = downloaded; + setChanged(); + notifyObservers(); + } + + public float getProgress() { + if (downloadSize == null) + return 0; + if (downloadSize == 0) + return 100; + return ((float) downloaded / downloadSize) * 100; + } + + public Status getStatus() { + return status; + } + + public void setStatus(Status status) { + this.status = status; + setChanged(); + notifyObservers(); + } + + public void download() throws InterruptedException { + RandomAccessFile file = null; + + try { + // Open file and seek to the end of it + file = new RandomAccessFile(outputFile, "rw"); + initialSize = file.length(); + file.seek(initialSize); + + setStatus(Status.CONNECTING); + + System.getProperties().remove("http.proxyHost"); + System.getProperties().remove("http.proxyPort"); + System.getProperties().remove("https.proxyHost"); + System.getProperties().remove("https.proxyPort"); + System.getProperties().remove("http.proxyUser"); + System.getProperties().remove("http.proxyPassword"); + + if (PreferencesData.has("proxy.http.server") && PreferencesData.get("proxy.http.server") != null && !PreferencesData.get("proxy.http.server").equals("")) { + System.getProperties().put("http.proxyHost", PreferencesData.get("proxy.http.server")); + System.getProperties().put("http.proxyPort", PreferencesData.get("proxy.http.port")); + } + if (PreferencesData.has("proxy.https.server") && PreferencesData.get("proxy.https.server") != null && !PreferencesData.get("proxy.https.server").equals("")) { + System.getProperties().put("https.proxyHost", PreferencesData.get("proxy.https.server")); + System.getProperties().put("https.proxyPort", PreferencesData.get("proxy.https.port")); + } + if (PreferencesData.has("proxy.user") && PreferencesData.get("proxy.user") != null && !PreferencesData.get("proxy.user").equals("")) { + System.getProperties().put("http.proxyUser", PreferencesData.get("proxy.user")); + System.getProperties().put("http.proxyPassword", PreferencesData.get("proxy.password")); + System.getProperties().put("https.proxyUser", PreferencesData.get("proxy.user")); + System.getProperties().put("https.proxyPassword", PreferencesData.get("proxy.password")); + } + + HttpURLConnection connection = (HttpURLConnection) downloadUrl.openConnection(); + + if (downloadUrl.getUserInfo() != null) { + String auth = "Basic " + new String(new Base64().encode(downloadUrl.getUserInfo().getBytes())); + connection.setRequestProperty("Authorization", auth); + } + + connection.setRequestProperty("Range", "bytes=" + initialSize + "-"); + connection.setConnectTimeout(5000); + setDownloaded(0); + + // Connect + connection.connect(); + int resp = connection.getResponseCode(); + + if (resp == HttpURLConnection.HTTP_MOVED_PERM || resp == HttpURLConnection.HTTP_MOVED_TEMP) { + String newUrl = connection.getHeaderField("Location"); + + // open the new connnection again + connection = (HttpURLConnection) new URL(newUrl).openConnection(); + if (downloadUrl.getUserInfo() != null) { + String auth = "Basic " + new String(new Base64().encode(downloadUrl.getUserInfo().getBytes())); + connection.setRequestProperty("Authorization", auth); + } + + connection.setRequestProperty("Range", "bytes=" + initialSize + "-"); + connection.setConnectTimeout(5000); + + connection.connect(); + resp = connection.getResponseCode(); + } + + if (resp < 200 || resp >= 300) { + throw new IOException("Recevied invalid http status code from server: " + resp); + } + + // Check for valid content length. + long len = connection.getContentLength(); + if (len >= 0) { + setDownloadSize(len); + } + setStatus(Status.DOWNLOADING); + + synchronized (this) { + stream = connection.getInputStream(); + } + byte buffer[] = new byte[10240]; + while (status == Status.DOWNLOADING) { + int read = stream.read(buffer); + if (read == -1) + break; + + file.write(buffer, 0, read); + setDownloaded(getDownloaded() + read); + + if (Thread.interrupted()) + throw new InterruptedException(); + } + + if (getDownloadSize() != null) { + if (getDownloaded() < getDownloadSize()) + throw new Exception("Incomplete download"); + } + setStatus(Status.COMPLETE); + } catch (InterruptedException e) { + setStatus(Status.CANCELLED); + // lets InterruptedException go up to the caller + throw e; + + } catch (SocketTimeoutException e) { + setStatus(Status.CONNECTION_TIMEOUT_ERROR); + setError(e); + + } catch (Exception e) { + setStatus(Status.ERROR); + setError(e); + + } finally { + if (file != null) { + try { + file.close(); + } catch (Exception e) { + //ignore + } + } + + synchronized (this) { + if (stream != null) { + try { + stream.close(); + } catch (Exception e) { + //ignore + } + } + } + } + } + + private void setError(Exception e) { + error = e; + } + + public Exception getError() { + return error; + } + + public boolean isCompleted() { + return status == Status.COMPLETE; + } +} diff --git a/arduino-core/src/processing/app/BaseNoGui.java b/arduino-core/src/processing/app/BaseNoGui.java index f90c7c4d9..da2fcfdd9 100644 --- a/arduino-core/src/processing/app/BaseNoGui.java +++ b/arduino-core/src/processing/app/BaseNoGui.java @@ -1,45 +1,53 @@ package processing.app; -import static processing.app.I18n._; +import cc.arduino.contributions.SignatureVerificationFailedException; +import cc.arduino.contributions.libraries.LibrariesIndexer; +import cc.arduino.contributions.packages.ContributedTool; +import cc.arduino.contributions.packages.ContributionsIndexer; +import cc.arduino.files.DeleteFilesOnShutdown; +import cc.arduino.packages.DiscoveryManager; +import cc.arduino.packages.Uploader; +import com.fasterxml.jackson.core.JsonProcessingException; +import org.apache.commons.logging.impl.LogFactoryImpl; +import org.apache.commons.logging.impl.NoOpLog; +import processing.app.debug.Compiler; +import processing.app.debug.*; +import processing.app.helpers.*; +import processing.app.helpers.filefilters.OnlyDirs; +import processing.app.helpers.filefilters.OnlyFilesWithExtension; +import processing.app.legacy.PApplet; +import processing.app.packages.LibraryList; +import processing.app.packages.UserLibrary; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileWriter; -import java.io.IOException; -import java.io.InputStream; +import java.io.*; import java.net.URISyntaxException; import java.util.*; import java.util.logging.Level; import java.util.logging.Logger; -import org.apache.commons.logging.impl.LogFactoryImpl; -import org.apache.commons.logging.impl.NoOpLog; - -import cc.arduino.packages.DiscoveryManager; -import cc.arduino.packages.Uploader; - -import processing.app.debug.Compiler; -import processing.app.debug.TargetBoard; -import processing.app.debug.TargetPackage; -import processing.app.debug.TargetPlatform; -import processing.app.debug.TargetPlatformException; -import processing.app.helpers.BasicUserNotifier; -import processing.app.helpers.CommandlineParser; -import processing.app.helpers.OSUtils; -import processing.app.helpers.PreferencesMap; -import processing.app.helpers.UserNotifier; -import processing.app.helpers.filefilters.OnlyDirs; -import processing.app.helpers.filefilters.OnlyFilesWithExtension; -import processing.app.legacy.PApplet; -import processing.app.packages.Library; -import processing.app.packages.LibraryList; +import static processing.app.I18n._; public class BaseNoGui { /** Version string to be used for build */ - public static final int REVISION = 10601; + public static final int REVISION = 10605; /** Extended version string displayed on GUI */ - static String VERSION_NAME = "1.6.1"; + public static final String VERSION_NAME = "1.6.5"; + public static final String VERSION_NAME_LONG; + + static { + String versionNameLong = VERSION_NAME; + File hourlyBuildTxt = new File(getContentFile("lib"), "hourlyBuild.txt"); + if (hourlyBuildTxt.exists() && hourlyBuildTxt.canRead()) { + versionNameLong += " Hourly Build"; + try { + versionNameLong += " " + FileUtils.readFileToString(hourlyBuildTxt).trim(); + } catch (IOException e) { + //noop + } + } + VERSION_NAME_LONG = versionNameLong; + } static File buildFolder; @@ -54,11 +62,12 @@ public class BaseNoGui { static private File toolsFolder; // maps #included files to their library folder - public static Map importToLibraryTable; + public static Map importToLibraryTable; // maps library name to their library folder static private LibraryList libraries; + // XXX: Remove this field static private List librariesFolders; static UserNotifier notifier = new BasicUserNotifier(); @@ -68,9 +77,11 @@ public class BaseNoGui { static Platform platform; static File portableFolder = null; - static final String portableSketchbookFolder = "sketchbook"; + public static ContributionsIndexer indexer; + static LibrariesIndexer librariesIndexer; + // Returns a File object for the given pathname. If the pathname // is not absolute, it is interpreted relative to the current // directory when starting the IDE (which is not the same as the @@ -139,7 +150,7 @@ public class BaseNoGui { //File folder = new File(getTempFolder(), "build"); //if (!folder.exists()) folder.mkdirs(); buildFolder = createTempFolder("build"); - buildFolder.deleteOnExit(); + DeleteFilesOnShutdown.add(buildFolder); } } return buildFolder; @@ -238,13 +249,6 @@ public class BaseNoGui { return librariesFolders; } - /** - * 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)); - } - static public Platform getPlatform() { return platform; } @@ -403,9 +407,8 @@ public class BaseNoGui { } static public LibraryList getUserLibs() { - if (libraries == null) - return new LibraryList(); - return libraries.filterLibrariesInSubfolder(getSketchbookFolder()); + LibraryList libs = BaseNoGui.librariesIndexer.getInstalledLibraries(); + return libs.filterLibrariesInSubfolder(getSketchbookFolder()); } /** @@ -421,7 +424,7 @@ public class BaseNoGui { return list; } - static public void init(String[] args) { + static public void init(String[] args) throws Exception { getPlatform().init(); String sketchbookPath = getSketchbookPath(); @@ -508,7 +511,7 @@ public class BaseNoGui { // - calls Sketch.build(verbose=false) that calls Sketch.ensureExistence(), set progressListener and calls Compiler.build() // - calls Sketch.upload() (see later...) if (!data.getFolder().exists()) showError(_("No sketch"), _("Can't find the sketch in the specified path"), null); - String suggestedClassName = Compiler.build(data, tempBuildFolder.getAbsolutePath(), tempBuildFolder, null, parser.isDoVerboseBuild()); + String suggestedClassName = Compiler.build(data, tempBuildFolder.getAbsolutePath(), tempBuildFolder, null, parser.isDoVerboseBuild(), false); if (suggestedClassName == null) showError(_("Error while verifying"), _("An error occurred while verifying the sketch"), null); showMessage(_("Done compiling"), _("Done compiling")); @@ -553,7 +556,7 @@ public class BaseNoGui { // if (!data.getFolder().exists()) showError(...); // String ... = Compiler.build(data, tempBuildFolder.getAbsolutePath(), tempBuildFolder, null, verbose); if (!data.getFolder().exists()) showError(_("No sketch"), _("Can't find the sketch in the specified path"), null); - String suggestedClassName = Compiler.build(data, tempBuildFolder.getAbsolutePath(), tempBuildFolder, null, parser.isDoVerboseBuild()); + String suggestedClassName = Compiler.build(data, tempBuildFolder.getAbsolutePath(), tempBuildFolder, null, parser.isDoVerboseBuild(), false); if (suggestedClassName == null) showError(_("Error while verifying"), _("An error occurred while verifying the sketch"), null); showMessage(_("Done compiling"), _("Done compiling")); } catch (Exception e) { @@ -582,13 +585,77 @@ public class BaseNoGui { Logger.getLogger("javax.jmdns").setLevel(Level.OFF); } - static public void initPackages() { + static public void initPackages() throws Exception { + indexer = new ContributionsIndexer(BaseNoGui.getSettingsFolder()); + File indexFile = indexer.getIndexFile("package_index.json"); + File defaultPackageJsonFile = new File(getContentFile("dist"), "package_index.json"); + if (!indexFile.isFile() || (defaultPackageJsonFile.isFile() && defaultPackageJsonFile.lastModified() > indexFile.lastModified())) { + FileUtils.copyFile(defaultPackageJsonFile, indexFile); + } else if (!indexFile.isFile()) { + // Otherwise create an empty packages index + FileOutputStream out = null; + try { + out = new FileOutputStream(indexFile); + out.write("{ \"packages\" : [ ] }".getBytes()); + out.close(); + } finally { + if (out != null) { + out.close(); + } + } + } + + File indexSignatureFile = indexer.getIndexFile("package_index.json.sig"); + File defaultPackageJsonSignatureFile = new File(getContentFile("dist"), "package_index.json.sig"); + if (!indexSignatureFile.isFile() || (defaultPackageJsonSignatureFile.isFile() && defaultPackageJsonSignatureFile.lastModified() > indexSignatureFile.lastModified())) { + FileUtils.copyFile(defaultPackageJsonSignatureFile, indexSignatureFile); + } + + try { + indexer.parseIndex(); + } catch (JsonProcessingException e) { + FileUtils.deleteIfExists(indexFile); + FileUtils.deleteIfExists(indexSignatureFile); + throw e; + } catch (SignatureVerificationFailedException e) { + FileUtils.deleteIfExists(indexFile); + FileUtils.deleteIfExists(indexSignatureFile); + throw e; + } + indexer.syncWithFilesystem(getHardwareFolder()); + packages = new HashMap(); loadHardware(getHardwareFolder()); loadHardware(getSketchbookHardwareFolder()); - if (packages.size() == 0) { - System.out.println(_("No valid configured cores found! Exiting...")); - System.exit(3); + loadContributedHardware(indexer); + createToolPreferences(indexer); + + librariesIndexer = new LibrariesIndexer(BaseNoGui.getSettingsFolder()); + File librariesIndexFile = librariesIndexer.getIndexFile(); + if (!librariesIndexFile.isFile()) { + File defaultLibraryJsonFile = new File(getContentFile("dist"), "library_index.json"); + if (defaultLibraryJsonFile.isFile()) { + FileUtils.copyFile(defaultLibraryJsonFile, librariesIndexFile); + } else { + FileOutputStream out = null; + try { + // Otherwise create an empty packages index + out = new FileOutputStream(librariesIndexFile); + out.write("{ \"libraries\" : [ ] }".getBytes()); + } catch (IOException e) { + e.printStackTrace(); + } finally { + if (out != null) { + out.close(); + } + } + } + } + try { + librariesIndexer.parseIndex(); + } catch (JsonProcessingException e) { + FileUtils.deleteIfExists(librariesIndexFile); + throw e; } } @@ -649,9 +716,9 @@ public class BaseNoGui { File subfolder = new File(folder, target); try { - packages.put(target, new TargetPackage(target, subfolder)); + packages.put(target, new LegacyTargetPackage(target, subfolder)); } catch (TargetPlatformException e) { - System.out.println("WARNING: Error loading hardware folder " + target); + System.out.println("WARNING: Error loading hardware folder " + new File(folder, target)); System.out.println(" " + e.getMessage()); } } @@ -670,6 +737,8 @@ public class BaseNoGui { if (args.length == 0) showError(_("No parameters"), _("No command line parameters found"), null); + Runtime.getRuntime().addShutdownHook(new Thread(DeleteFilesOnShutdown.INSTANCE)); + initPlatform(); initPortableFolder(); @@ -683,9 +752,10 @@ public class BaseNoGui { examplesFolder = getContentFile("examples"); toolsFolder = getContentFile("tools"); librariesFolders = new ArrayList(); + + // Add IDE libraries folder librariesFolders.add(getContentFile("libraries")); - // Add library folder for the current selected platform TargetPlatform targetPlatform = getTargetPlatform(); if (targetPlatform != null) { String core = getBoardPreferences().get("build.core", "arduino"); @@ -694,35 +764,69 @@ public class BaseNoGui { TargetPlatform referencedPlatform = getTargetPlatform(referencedCore, targetPlatform.getId()); if (referencedPlatform != null) { File referencedPlatformFolder = referencedPlatform.getFolder(); - librariesFolders.add(new File(referencedPlatformFolder, "libraries")); + // Add libraries folder for the referenced platform + File folder = new File(referencedPlatformFolder, "libraries"); + librariesFolders.add(folder); } } File platformFolder = targetPlatform.getFolder(); - librariesFolders.add(new File(platformFolder, "libraries")); - librariesFolders.add(getSketchbookLibrariesFolder()); + // Add libraries folder for the selected platform + File folder = new File(platformFolder, "libraries"); + librariesFolders.add(folder); } + // Add libraries folder for the sketchbook + librariesFolders.add(getSketchbookLibrariesFolder()); + // Scan for libraries in each library folder. // Libraries located in the latest folders on the list can override // other libraries with the same name. - try { - scanAndUpdateLibraries(librariesFolders); - } catch (IOException e) { - showWarning(_("Error"), _("Error loading libraries"), e); - } + BaseNoGui.librariesIndexer.setSketchbookLibrariesFolder(getSketchbookLibrariesFolder()); + BaseNoGui.librariesIndexer.setLibrariesFolders(librariesFolders); + BaseNoGui.librariesIndexer.rescanLibraries(); populateImportToLibraryTable(); } + static protected void loadContributedHardware(ContributionsIndexer indexer) throws TargetPlatformException { + for (TargetPackage pack : indexer.createTargetPackages()) { + packages.put(pack.getId(), pack); + } + } + + static private void createToolPreferences(ContributionsIndexer indexer) { + // Remove previous runtime preferences + final String prefix = "runtime.tools."; + PreferencesData.removeAllKeysWithPrefix(prefix); + + for (ContributedTool tool : indexer.getInstalledTools()) { + File installedFolder = tool.getDownloadableContribution().getInstalledFolder(); + if (installedFolder != null) { + PreferencesData.set(prefix + tool.getName() + ".path", installedFolder.getAbsolutePath()); + PreferencesData.set(prefix + tool.getName() + "-" + tool.getVersion() + ".path", installedFolder.getAbsolutePath()); + } + } + } + static public void populateImportToLibraryTable() { - // Populate importToLibraryTable - importToLibraryTable = new HashMap(); - for (Library lib : getLibraries()) { + // Populate importToLibraryTable. Each header filename maps to + // a list of libraries. Compiler.java will use only the first + // library on each list. The others are used only to advise + // user of ambiguously matched and duplicate libraries. + importToLibraryTable = new HashMap(); + for (UserLibrary lib : librariesIndexer.getInstalledLibraries()) { try { String headers[] = headerListFromIncludePath(lib.getSrcFolder()); for (String header : headers) { - Library old = importToLibraryTable.get(header); - if (old != null) { + LibraryList list = importToLibraryTable.get(header); + if (list == null) { + // This is the first library found with this header + list = new LibraryList(); + list.addFirst(lib); + importToLibraryTable.put(header, list); + } else { + UserLibrary old = list.peekFirst(); + boolean useThisLib = true; // This is the case where 2 libraries have a .h header // with the same name. We must decide which library to // use when a sketch has #include "name.h" @@ -737,61 +841,84 @@ public class BaseNoGui { // for "libName", then for "oldName". // String name = header.substring(0, header.length() - 2); // name without ".h" - String oldName = old.getFolder().getName(); // just the library folder name - String libName = lib.getFolder().getName(); // just the library folder name + String oldName = old.getInstalledFolder().getName(); // just the library folder name + String libName = lib.getInstalledFolder().getName(); // just the library folder name //System.out.println("name conflict: " + name); - //System.out.println(" old = " + oldName + " -> " + old.getFolder().getPath()); - //System.out.println(" new = " + libName + " -> " + lib.getFolder().getPath()); + //System.out.println(" old = " + oldName + " -> " + old.getInstalledFolder().getPath()); + //System.out.println(" new = " + libName + " -> " + lib.getInstalledFolder().getPath()); String name_lc = name.toLowerCase(); String oldName_lc = oldName.toLowerCase(); String libName_lc = libName.toLowerCase(); // always favor a perfect name match if (libName.equals(name)) { } else if (oldName.equals(name)) { - continue; + useThisLib = false; // check for "-master" appended (zip file from github) } else if (libName.equals(name+"-master")) { } else if (oldName.equals(name+"-master")) { - continue; + useThisLib = false; // next, favor a match with other stuff appended } else if (libName.startsWith(name)) { } else if (oldName.startsWith(name)) { - continue; + useThisLib = false; // otherwise, favor a match with stuff prepended } else if (libName.endsWith(name)) { } else if (oldName.endsWith(name)) { - continue; + useThisLib = false; // as a last resort, match if stuff prepended and appended } else if (libName.contains(name)) { } else if (oldName.contains(name)) { - continue; + useThisLib = false; // repeat all the above tests, with case insensitive matching } else if (libName_lc.equals(name_lc)) { } else if (oldName_lc.equals(name_lc)) { - continue; + useThisLib = false; } else if (libName_lc.equals(name_lc+"-master")) { } else if (oldName_lc.equals(name_lc+"-master")) { - continue; + useThisLib = false; } else if (libName_lc.startsWith(name_lc)) { } else if (oldName_lc.startsWith(name_lc)) { - continue; + useThisLib = false; } else if (libName_lc.endsWith(name_lc)) { } else if (oldName_lc.endsWith(name_lc)) { - continue; + useThisLib = false; } else if (libName_lc.contains(name_lc)) { } else if (oldName_lc.contains(name_lc)) { - continue; + useThisLib = false; } else { // none of these tests matched, so just default to "libName". } + if (useThisLib) { + list.addFirst(lib); + } else { + list.addLast(lib); + } } - importToLibraryTable.put(header, lib); } } catch (IOException e) { showWarning(_("Error"), I18n .format("Unable to list header files in {0}", lib.getSrcFolder()), e); } } + // repeat for ALL libraries, to pick up duplicates not visible normally. + // any new libraries found here are NEVER used, but they are added to the + // end of already-found headers, to allow Compiler to report them if + // the sketch tries to use them. + for (UserLibrary lib : librariesIndexer.getInstalledLibrariesWithDuplicates()) { + try { + String headers[] = headerListFromIncludePath(lib.getSrcFolder()); + for (String header : headers) { + LibraryList list = importToLibraryTable.get(header); + if (list != null) { + if (!(list.hasLibrary(lib))) { + list.addLast(lib); + //System.out.println(" duplicate lib: " + lib.getInstalledFolder().getPath()); + } + } + } + } catch (IOException e) { + } + } } static public void initParameters(String args[]) { @@ -926,49 +1053,6 @@ public class BaseNoGui { } } - static public void scanAndUpdateLibraries(List folders) throws IOException { - libraries = scanLibraries(folders); - } - - static public LibraryList scanLibraries(List folders) throws IOException { - LibraryList res = new LibraryList(); - for (File folder : folders) - res.addOrReplaceAll(scanLibraries(folder)); - return res; - } - - static public LibraryList scanLibraries(File folder) throws IOException { - LibraryList res = new LibraryList(); - - String list[] = folder.list(new OnlyDirs()); - // if a bad folder or something like that, this might come back null - if (list == null) - return res; - - for (String libName : list) { - File subfolder = new File(folder, libName); - if (!isSanitaryName(libName)) { - String mess = I18n.format(_("The library \"{0}\" 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)"), - libName); - showMessage(_("Ignoring bad library name"), mess); - continue; - } - - try { - Library lib = Library.create(subfolder); - // (also replace previously found libs with the same name) - if (lib != null) - res.addOrReplace(lib); - } catch (IOException e) { - System.out.println(I18n.format(_("Invalid library found in {0}: {1}"), - subfolder, e.getMessage())); - } - } - return res; - } - static public void selectBoard(TargetBoard targetBoard) { TargetPlatform targetPlatform = targetBoard.getContainerPlatform(); TargetPackage targetPackage = targetPlatform.getContainerPackage(); diff --git a/arduino-core/src/processing/app/I18n.java b/arduino-core/src/processing/app/I18n.java index d6480d99e..ef71ce365 100644 --- a/arduino-core/src/processing/app/I18n.java +++ b/arduino-core/src/processing/app/I18n.java @@ -24,11 +24,11 @@ public class I18n { // prompt text stuff - static String PROMPT_YES; - static String PROMPT_NO; - static String PROMPT_CANCEL; - static String PROMPT_OK; - static String PROMPT_BROWSE; + public static String PROMPT_YES; + public static String PROMPT_NO; + public static String PROMPT_CANCEL; + public static String PROMPT_OK; + public static String PROMPT_BROWSE; static protected void init(String language) throws MissingResourceException { String[] languageParts = language.split("_"); diff --git a/arduino-core/src/processing/app/Platform.java b/arduino-core/src/processing/app/Platform.java index 3c46c095d..b2deee2f8 100644 --- a/arduino-core/src/processing/app/Platform.java +++ b/arduino-core/src/processing/app/Platform.java @@ -21,24 +21,19 @@ */ package processing.app; -import static processing.app.I18n._; - -import java.io.File; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -import javax.swing.UIManager; import cc.arduino.packages.BoardPort; -import com.sun.jna.Library; -import com.sun.jna.Native; import processing.app.debug.TargetBoard; import processing.app.debug.TargetPackage; import processing.app.debug.TargetPlatform; import processing.app.legacy.PConstants; +import javax.swing.*; +import java.io.*; +import java.util.*; + +import static processing.app.I18n._; + /** * Used by Base for platform-specific tweaking, for instance finding the @@ -75,7 +70,7 @@ public class Platform { } - public void init() { + public void init() throws IOException { } @@ -169,6 +164,8 @@ public class Platform { } public String resolveDeviceByBoardID(Map packages, String boardId) { + assert packages != null; + assert boardId != null; for (TargetPackage targetPackage : packages.values()) { for (TargetPlatform targetPlatform : targetPackage.getPlatforms().values()) { for (TargetBoard board : targetPlatform.getBoards().values()) { @@ -183,33 +180,6 @@ public class Platform { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . - - public interface CLibrary extends Library { - CLibrary INSTANCE = (CLibrary)Native.loadLibrary("c", CLibrary.class); - int setenv(String name, String value, int overwrite); - String getenv(String name); - int unsetenv(String name); - int putenv(String string); - } - - - public void setenv(String variable, String value) { - CLibrary clib = CLibrary.INSTANCE; - clib.setenv(variable, value, 1); - } - - - public String getenv(String variable) { - CLibrary clib = CLibrary.INSTANCE; - return clib.getenv(variable); - } - - - public int unsetenv(String variable) { - CLibrary clib = CLibrary.INSTANCE; - return clib.unsetenv(variable); - } - public String getName() { return PConstants.platformNames[PConstants.OTHER]; } @@ -227,4 +197,39 @@ public class Platform { public List filterPorts(List ports, boolean aBoolean) { return new LinkedList(ports); } + + public void fixPrefsFilePermissions(File prefsFile) throws IOException, InterruptedException { + Process process = Runtime.getRuntime().exec(new String[]{"chmod", "600", prefsFile.getAbsolutePath()}, null, null); + process.waitFor(); + } + + public List postInstallScripts(File folder) { + List scripts = new LinkedList(); + scripts.add(new File(folder, "install_script.sh")); + scripts.add(new File(folder, "post_install.sh")); + return scripts; + } + + public String getOsName() { + return System.getProperty("os.name"); + } + + public String getOsArch() { + return System.getProperty("os.arch"); + } + + public void symlink(String something, File somewhere) throws IOException, InterruptedException { + Process process = Runtime.getRuntime().exec(new String[]{"ln", "-s", something, somewhere.getAbsolutePath()}, null, somewhere.getParentFile()); + process.waitFor(); + } + + public void link(File something, File somewhere) throws IOException, InterruptedException { + Process process = Runtime.getRuntime().exec(new String[]{"ln", something.getAbsolutePath(), somewhere.getAbsolutePath()}, null, null); + process.waitFor(); + } + + public void chmod(File file, int mode) throws IOException, InterruptedException { + Process process = Runtime.getRuntime().exec(new String[]{"chmod", Integer.toOctalString(mode), file.getAbsolutePath()}, null, null); + process.waitFor(); + } } diff --git a/arduino-core/src/processing/app/PreferencesData.java b/arduino-core/src/processing/app/PreferencesData.java index 94cc187c8..7733b08e4 100644 --- a/arduino-core/src/processing/app/PreferencesData.java +++ b/arduino-core/src/processing/app/PreferencesData.java @@ -2,6 +2,7 @@ package processing.app; import static processing.app.I18n._; +import java.awt.*; import java.io.BufferedReader; import java.io.File; import java.io.IOException; @@ -9,8 +10,10 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintWriter; import java.util.Arrays; +import java.util.Iterator; import java.util.MissingResourceException; +import processing.app.helpers.PreferencesHelper; import processing.app.helpers.PreferencesMap; import processing.app.legacy.PApplet; import processing.app.legacy.PConstants; @@ -18,7 +21,7 @@ import processing.app.legacy.PConstants; public class PreferencesData { - static final String PREFS_FILE = "preferences.txt"; + private static final String PREFS_FILE = "preferences.txt"; // data model @@ -29,18 +32,25 @@ public class PreferencesData { static public void init(File file) { - if (file != null) + if (file != null) { preferencesFile = file; - else + } else { preferencesFile = BaseNoGui.getSettingsFile(PREFS_FILE); + } + + try { + BaseNoGui.getPlatform().fixPrefsFilePermissions(preferencesFile); + } catch (Exception e) { + //ignore + } // start by loading the defaults, in case something // important was deleted from the user prefs try { - prefs.load(BaseNoGui.getLibStream("preferences.txt")); + prefs.load(new File(BaseNoGui.getContentFile("lib"), PREFS_FILE)); } catch (IOException e) { BaseNoGui.showError(null, _("Could not read default settings.\n" + - "You'll need to reinstall Arduino."), e); + "You'll need to reinstall Arduino."), e); } // set some runtime constants (not saved on preferences file) @@ -78,6 +88,10 @@ public class PreferencesData { fixPreferences(); } + public static File getPreferencesFile() { + return preferencesFile; + } + private static void fixPreferences() { String baud = get("serial.debug_rate"); if ("14400".equals(baud) || "28800".equals(baud)) { @@ -86,41 +100,6 @@ public class PreferencesData { } - static public String[] loadStrings(InputStream input) { - try { - BufferedReader reader = - new BufferedReader(new InputStreamReader(input, "UTF-8")); - - String lines[] = new String[100]; - int lineCount = 0; - String line = null; - while ((line = reader.readLine()) != null) { - if (lineCount == lines.length) { - String temp[] = new String[lineCount << 1]; - System.arraycopy(lines, 0, temp, 0, lineCount); - lines = temp; - } - lines[lineCount++] = line; - } - reader.close(); - - if (lineCount == lines.length) { - return lines; - } - - // resize array to appropriate amount for these lines - String output[] = new String[lineCount]; - System.arraycopy(lines, 0, output, 0, lineCount); - return output; - - } catch (IOException e) { - e.printStackTrace(); - //throw new RuntimeException("Error inside loadStrings()"); - } - return null; - } - - static protected void save() { if (!doSave) return; @@ -131,18 +110,30 @@ public class PreferencesData { if (preferencesFile == null) return; // Fix for 0163 to properly use Unicode when writing preferences.txt - PrintWriter writer = PApplet.createWriter(preferencesFile); + PrintWriter writer = null; + try { + writer = PApplet.createWriter(preferencesFile); - String[] keys = prefs.keySet().toArray(new String[0]); - Arrays.sort(keys); - for (String key: keys) { - if (key.startsWith("runtime.")) - continue; - writer.println(key + "=" + prefs.get(key)); + String[] keys = prefs.keySet().toArray(new String[0]); + Arrays.sort(keys); + for (String key : keys) { + if (key.startsWith("runtime.")) + continue; + writer.println(key + "=" + prefs.get(key)); + } + + writer.flush(); + } finally { + if (writer != null) { + writer.close(); + } } - writer.flush(); - writer.close(); + try { + BaseNoGui.getPlatform().fixPrefsFilePermissions(preferencesFile); + } catch (Exception e) { + //ignore + } } @@ -194,6 +185,13 @@ public class PreferencesData { return Integer.parseInt(get(attribute)); } + static public int getInteger(String attribute, int defaultValue) { + if (has(attribute)) { + return getInteger(attribute); + } + + return defaultValue; + } static public void setInteger(String key, int value) { set(key, String.valueOf(value)); @@ -205,10 +203,27 @@ public class PreferencesData { return new PreferencesMap(prefs); } + static public void removeAllKeysWithPrefix(String prefix) { + Iterator keys = prefs.keySet().iterator(); + while (keys.hasNext()) + if (keys.next().startsWith(prefix)) + keys.remove(); + } + // Decide wether changed preferences will be saved. When value is // false, Preferences.save becomes a no-op. static public void setDoSave(boolean value) { doSave = value; } + + static public Font getFont(String attr) { + Font font = PreferencesHelper.getFont(prefs, attr); + if (font == null) { + String value = defaults.get(attr); + prefs.put(attr, value); + font = PreferencesHelper.getFont(prefs, attr); + } + return font; + } } diff --git a/arduino-core/src/processing/app/Serial.java b/arduino-core/src/processing/app/Serial.java index 90065de33..e442299d3 100644 --- a/arduino-core/src/processing/app/Serial.java +++ b/arduino-core/src/processing/app/Serial.java @@ -88,11 +88,12 @@ public class Serial implements SerialPortEventListener { BaseNoGui.getBoardPreferences().get("serial.disableDTR") == null); } - public static boolean touchPort(String iname, int irate) throws SerialException { + public static boolean touchForCDCReset(String iname) throws SerialException { SerialPort serialPort = new SerialPort(iname); try { serialPort.openPort(); - serialPort.setParams(irate, 8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); + serialPort.setParams(1200, 8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); + serialPort.setDTR(false); serialPort.closePort(); return true; } catch (SerialPortException e) { diff --git a/arduino-core/src/processing/app/debug/Compiler.java b/arduino-core/src/processing/app/debug/Compiler.java index e84ba4eda..b37876ddd 100644 --- a/arduino-core/src/processing/app/debug/Compiler.java +++ b/arduino-core/src/processing/app/debug/Compiler.java @@ -25,13 +25,7 @@ package processing.app.debug; import static processing.app.I18n._; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.FileReader; -import java.io.IOException; -import java.io.PrintWriter; +import java.io.*; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -45,6 +39,9 @@ import cc.arduino.packages.BoardPort; import cc.arduino.packages.Uploader; import cc.arduino.packages.UploaderFactory; +import org.apache.commons.exec.CommandLine; +import org.apache.commons.exec.DefaultExecutor; +import org.apache.commons.exec.ExecuteStreamHandler; import processing.app.BaseNoGui; import processing.app.I18n; import processing.app.PreferencesData; @@ -52,10 +49,12 @@ import processing.app.SketchCode; import processing.app.SketchData; import processing.app.helpers.*; import processing.app.helpers.filefilters.OnlyDirs; -import processing.app.packages.Library; import processing.app.packages.LibraryList; import processing.app.preproc.PdePreprocessor; import processing.app.legacy.PApplet; +import processing.app.packages.LegacyUserLibrary; +import processing.app.packages.UserLibrary; +import processing.app.tools.DoubleQuotedArgumentsOnWindowsCommandLine; public class Compiler implements MessageConsumer { @@ -68,6 +67,7 @@ public class Compiler implements MessageConsumer { private SketchData sketch; private PreferencesMap prefs; private boolean verbose; + private boolean saveHex; private List objectFiles; @@ -84,7 +84,7 @@ public class Compiler implements MessageConsumer { private ProgressListener progressListener; - static public String build(SketchData data, String buildPath, File tempBuildFolder, ProgressListener progListener, boolean verbose) throws RunnerException, PreferencesMapException { + static public String build(SketchData data, String buildPath, File tempBuildFolder, ProgressListener progListener, boolean verbose, boolean save) throws RunnerException, PreferencesMapException { if (SketchData.checkSketchFile(data.getPrimaryFile()) == null) BaseNoGui.showError(_("Bad file selected"), _("Bad sketch primary file or bad sketch directory structure"), null); @@ -113,9 +113,16 @@ public class Compiler implements MessageConsumer { // compile the program. errors will happen as a RunnerException // that will bubble up to whomever called build(). - if (compiler.compile(verbose)) { - compiler.size(compiler.getBuildPreferences()); - return primaryClassName; + try { + if (compiler.compile(verbose, save)) { + compiler.size(compiler.getBuildPreferences()); + return primaryClassName; + } + } catch (RunnerException e) { + // when the compile fails, take this opportunity to show + // any helpful info possible before throwing the exception + compiler.adviseDuplicateLibraries(); + throw e; } return null; } @@ -183,6 +190,9 @@ public class Compiler implements MessageConsumer { sketch = _sketch; prefs = createBuildPreferences(_buildPath, _primaryClassName); + // provide access to the source tree + prefs.put("build.source.path", _sketch.getFolder().getAbsolutePath()); + // Start with an empty progress listener progressListener = new ProgressListener() { @Override @@ -311,10 +321,10 @@ public class Compiler implements MessageConsumer { if (maxDataSize > 0) { System.out .println(I18n - .format( - _("Global variables use {0} bytes ({2}%%) of dynamic memory, leaving {3} bytes for local variables. Maximum is {1} bytes."), - dataSize, maxDataSize, dataSize * 100 / maxDataSize, - maxDataSize - dataSize)); + .format( + _("Global variables use {0} bytes ({2}%%) of dynamic memory, leaving {3} bytes for local variables. Maximum is {1} bytes."), + dataSize, maxDataSize, dataSize * 100 / maxDataSize, + maxDataSize - dataSize)); } else { System.out.println(I18n .format(_("Global variables use {0} bytes of dynamic memory."), dataSize)); @@ -341,11 +351,16 @@ public class Compiler implements MessageConsumer { * @return true if successful. * @throws RunnerException Only if there's a problem. Only then. */ - public boolean compile(boolean _verbose) throws RunnerException, PreferencesMapException { + public boolean compile(boolean _verbose, boolean _save) throws RunnerException, PreferencesMapException { preprocess(prefs.get("build.path")); verbose = _verbose || PreferencesData.getBoolean("build.verbose"); + saveHex = _save; sketchIsCompiled = false; + + // Hook runs at Start of Compilation + runActions("hooks.prebuild", prefs); + objectFiles = new ArrayList(); // 0. include paths for core + all libraries @@ -354,11 +369,15 @@ public class Compiler implements MessageConsumer { includeFolders.add(prefs.getFile("build.core.path")); if (prefs.getFile("build.variant.path") != null) includeFolders.add(prefs.getFile("build.variant.path")); - for (Library lib : importedLibraries) { - if (verbose) + for (UserLibrary lib : importedLibraries) { + if (verbose) { + String legacy = ""; + if (lib instanceof LegacyUserLibrary) + legacy = "(legacy)"; System.out.println(I18n .format(_("Using library {0} in folder: {1} {2}"), lib.getName(), - lib.getFolder(), lib.isLegacy() ? "(legacy)" : "")); + lib.getInstalledFolder(), legacy)); + } includeFolders.add(lib.getSrcFolder()); } if (verbose) @@ -370,7 +389,7 @@ public class Compiler implements MessageConsumer { String[] overrides = prefs.get("architecture.override_check").split(","); archs.addAll(Arrays.asList(overrides)); } - for (Library lib : importedLibraries) { + for (UserLibrary lib : importedLibraries) { if (!lib.supportsArchitecture(archs)) { System.err.println(I18n .format(_("WARNING: library {0} claims to run on {1} " @@ -382,26 +401,26 @@ public class Compiler implements MessageConsumer { } // 1. compile the sketch (already in the buildPath) - progressListener.progress(30); + progressListener.progress(20); compileSketch(includeFolders); sketchIsCompiled = true; // 2. compile the libraries, outputting .o files to: // // Doesn't really use configPreferences - progressListener.progress(40); + progressListener.progress(30); compileLibraries(includeFolders); // 3. compile the core, outputting .o files to and then // collecting them into the core.a library file. - progressListener.progress(50); + progressListener.progress(40); compileCore(); // 4. link it all together into the .elf file - progressListener.progress(60); + progressListener.progress(50); compileLink(); // 5. run objcopy to generate output files - progressListener.progress(75); + progressListener.progress(60); List objcopyPatterns = new ArrayList(); for (String key : prefs.keySet()) { if (key.startsWith("recipe.objcopy.") && key.endsWith(".pattern")) @@ -412,10 +431,39 @@ public class Compiler implements MessageConsumer { runRecipe(recipe); } + // 7. save the hex file + if (saveHex) { + progressListener.progress(80); + saveHex(); + } + progressListener.progress(90); + + // Hook runs at End of Compilation + runActions("hooks.postbuild", prefs); + adviseDuplicateLibraries(); + return true; } + private void adviseDuplicateLibraries() { + for (int i=0; i < importedDuplicateHeaders.size(); i++) { + System.out.println(I18n.format(_("Multiple libraries were found for \"{0}\""), + importedDuplicateHeaders.get(i))); + boolean first = true; + for (UserLibrary lib : importedDuplicateLibraries.get(i)) { + if (first) { + System.out.println(I18n.format(_(" Used: {0}"), + lib.getInstalledFolder().getPath())); + first = false; + } else { + System.out.println(I18n.format(_(" Not used: {0}"), + lib.getInstalledFolder().getPath())); + } + } + } + } + private PreferencesMap createBuildPreferences(String _buildPath, String _primaryClassName) throws RunnerException { @@ -460,6 +508,13 @@ public class Compiler implements MessageConsumer { p.put("build.path", _buildPath); p.put("build.project_name", _primaryClassName); p.put("build.arch", targetPlatform.getId().toUpperCase()); + File sketch_data = sketch.getDataFolder(); + if(sketch_data.exists()){ + p.put("build.sketch_data", sketch_data.getAbsolutePath()); + } else { + p.put("build.sketch_data", ""); + } + // Platform.txt should define its own compiler.path. For // compatibility with earlier 1.5 versions, we define a (ugly, @@ -640,7 +695,6 @@ public class Compiler implements MessageConsumer { command = stringList.toArray(new String[stringList.size()]); if (command.length == 0) return; - int result = 0; if (verbose) { for (String c : command) @@ -648,30 +702,57 @@ public class Compiler implements MessageConsumer { System.out.println(); } - Process process; + DefaultExecutor executor = new DefaultExecutor(); + executor.setStreamHandler(new ExecuteStreamHandler() { + @Override + public void setProcessInputStream(OutputStream os) throws IOException { + + } + + @Override + public void setProcessErrorStream(InputStream is) throws IOException { + forwardToMessage(is); + } + + @Override + public void setProcessOutputStream(InputStream is) throws IOException { + forwardToMessage(is); + } + + private void forwardToMessage(InputStream is) throws IOException { + BufferedReader reader = new BufferedReader(new InputStreamReader(is)); + String line; + while ((line = reader.readLine()) != null) { + message(line + "\n"); + } + } + + @Override + public void start() throws IOException { + + } + + @Override + public void stop() { + + } + }); + + CommandLine commandLine = new DoubleQuotedArgumentsOnWindowsCommandLine(command[0]); + for (int i = 1; i < command.length; i++) { + commandLine.addArgument(command[i], false); + } + + int result; + executor.setExitValues(null); try { - process = ProcessUtils.exec(command); + result = executor.execute(commandLine); } catch (IOException e) { RunnerException re = new RunnerException(e.getMessage()); re.hideStackTrace(); throw re; } - - MessageSiphon in = new MessageSiphon(process.getInputStream(), this); - MessageSiphon err = new MessageSiphon(process.getErrorStream(), this); - - // wait for the process to finish. if interrupted - // before waitFor returns, continue waiting - boolean compiling = true; - while (compiling) { - try { - in.join(); - err.join(); - result = process.waitFor(); - //System.out.println("result is " + result); - compiling = false; - } catch (InterruptedException ignored) { } - } + executor.setExitValues(new int[0]); // an error was queued up by message(), barf this back to compile(), // which will barf it back to Editor. if you're having trouble @@ -713,10 +794,10 @@ public class Compiler implements MessageConsumer { s = s.substring(0, i) + s.substring(i + (buildPath + File.separator).length()); } } - + // look for error line, which contains file name, line number, // and at least the first line of the error message - String errorFormat = "([\\w\\d_]+.\\w+):(\\d+):\\s*error:\\s*(.*)\\s*"; + String errorFormat = "(.+\\.\\w+):(\\d+)(:\\d+)*:\\s*error:\\s*(.*)\\s*"; String[] pieces = PApplet.match(s, errorFormat); // if (pieces != null && exception == null) { @@ -725,56 +806,56 @@ public class Compiler implements MessageConsumer { // } if (pieces != null) { - String error = pieces[3], msg = ""; + String error = pieces[pieces.length - 1], msg = ""; - if (pieces[3].trim().equals("SPI.h: No such file or directory")) { + if (error.trim().equals("SPI.h: No such file or directory")) { error = _("Please import the SPI library from the Sketch > Import Library menu."); msg = _("\nAs of Arduino 0019, the Ethernet library depends on the SPI library." + "\nYou appear to be using it or another library that depends on the SPI library.\n\n"); } - if (pieces[3].trim().equals("'BYTE' was not declared in this scope")) { + if (error.trim().equals("'BYTE' was not declared in this scope")) { error = _("The 'BYTE' keyword is no longer supported."); msg = _("\nAs of Arduino 1.0, the 'BYTE' keyword is no longer supported." + "\nPlease use Serial.write() instead.\n\n"); } - if (pieces[3].trim().equals("no matching function for call to 'Server::Server(int)'")) { + if (error.trim().equals("no matching function for call to 'Server::Server(int)'")) { error = _("The Server class has been renamed EthernetServer."); msg = _("\nAs of Arduino 1.0, the Server class in the Ethernet library " + "has been renamed to EthernetServer.\n\n"); } - if (pieces[3].trim().equals("no matching function for call to 'Client::Client(byte [4], int)'")) { + if (error.trim().equals("no matching function for call to 'Client::Client(byte [4], int)'")) { error = _("The Client class has been renamed EthernetClient."); msg = _("\nAs of Arduino 1.0, the Client class in the Ethernet library " + "has been renamed to EthernetClient.\n\n"); } - if (pieces[3].trim().equals("'Udp' was not declared in this scope")) { + if (error.trim().equals("'Udp' was not declared in this scope")) { error = _("The Udp class has been renamed EthernetUdp."); msg = _("\nAs of Arduino 1.0, the Udp class in the Ethernet library " + "has been renamed to EthernetUdp.\n\n"); } - if (pieces[3].trim().equals("'class TwoWire' has no member named 'send'")) { + if (error.trim().equals("'class TwoWire' has no member named 'send'")) { error = _("Wire.send() has been renamed Wire.write()."); msg = _("\nAs of Arduino 1.0, the Wire.send() function was renamed " + "to Wire.write() for consistency with other libraries.\n\n"); } - if (pieces[3].trim().equals("'class TwoWire' has no member named 'receive'")) { + if (error.trim().equals("'class TwoWire' has no member named 'receive'")) { error = _("Wire.receive() has been renamed Wire.read()."); msg = _("\nAs of Arduino 1.0, the Wire.receive() function was renamed " + "to Wire.read() for consistency with other libraries.\n\n"); } - if (pieces[3].trim().equals("'Mouse' was not declared in this scope")) { + if (error.trim().equals("'Mouse' was not declared in this scope")) { error = _("'Mouse' only supported on the Arduino Leonardo"); //msg = _("\nThe 'Mouse' class is only supported on the Arduino Leonardo.\n\n"); } - if (pieces[3].trim().equals("'Keyboard' was not declared in this scope")) { + if (error.trim().equals("'Keyboard' was not declared in this scope")) { error = _("'Keyboard' only supported on the Arduino Leonardo"); //msg = _("\nThe 'Keyboard' class is only supported on the Arduino Leonardo.\n\n"); } @@ -792,13 +873,15 @@ public class Compiler implements MessageConsumer { SketchCode code = sketch.getCode(e.getCodeIndex()); String fileName = (code.isExtension("ino") || code.isExtension("pde")) ? code.getPrettyName() : code.getFileName(); int lineNum = e.getCodeLine() + 1; - s = fileName + ":" + lineNum + ": error: " + pieces[3] + msg; + s = fileName + ":" + lineNum + ": error: " + error + msg; + } + + if (e != null) { + if (exception == null || exception.getMessage().equals(e.getMessage())) { + exception = e; + exception.hideStackTrace(); + } } - - if (exception == null && e != null) { - exception = e; - exception.hideStackTrace(); - } } if (s.contains("undefined reference to `SPIClass::begin()'") && @@ -824,6 +907,8 @@ public class Compiler implements MessageConsumer { dict.put("source_file", sourceFile.getAbsolutePath()); dict.put("object_file", objectFile.getAbsolutePath()); + setupWarningFlags(dict); + String cmd = prefs.getOrExcept(recipe); try { return StringReplacer.formatAndSplit(cmd, dict, true); @@ -832,6 +917,19 @@ public class Compiler implements MessageConsumer { } } + private void setupWarningFlags(PreferencesMap dict) { + if (dict.containsKey("compiler.warning_level")) { + String key = "compiler.warning_flags." + dict.get("compiler.warning_level"); + dict.put("compiler.warning_flags", dict.get(key)); + } else { + dict.put("compiler.warning_flags", dict.get("compiler.warning_flags.none")); + } + + if (dict.get("compiler.warning_flags") == null) { + dict.remove("compiler.warning_flags"); + } + } + ///////////////////////////////////////////////////////////////////////////// private void createFolder(File folder) throws RunnerException { @@ -879,21 +977,21 @@ public class Compiler implements MessageConsumer { // 2. compile the libraries, outputting .o files to: // // void compileLibraries(List includeFolders) throws RunnerException, PreferencesMapException { - for (Library lib : importedLibraries) { + for (UserLibrary lib : importedLibraries) { compileLibrary(lib, includeFolders); } } - private void compileLibrary(Library lib, List includeFolders) + private void compileLibrary(UserLibrary lib, List includeFolders) throws RunnerException, PreferencesMapException { File libFolder = lib.getSrcFolder(); File libBuildFolder = prefs.getFile(("build.path"), lib.getName()); - + if (lib.useRecursion()) { // libBuildFolder == {build.path}/LibName // libFolder == {lib.path}/src recursiveCompileFilesInFolder(libBuildFolder, libFolder, includeFolders); - + } else { // libFolder == {lib.path}/ // utilityFolder == {lib.path}/utility @@ -901,11 +999,11 @@ public class Compiler implements MessageConsumer { // utilityBuildFolder == {build.path}/LibName/utility File utilityFolder = new File(libFolder, "utility"); File utilityBuildFolder = new File(libBuildFolder, "utility"); - + includeFolders.add(utilityFolder); compileFilesInFolder(libBuildFolder, libFolder, includeFolders); compileFilesInFolder(utilityBuildFolder, utilityFolder, includeFolders); - + // other libraries should not see this library's utility/ folder includeFolders.remove(utilityFolder); } @@ -1024,6 +1122,8 @@ public class Compiler implements MessageConsumer { dict.put("object_files", objectFileList); dict.put("ide_version", "" + BaseNoGui.REVISION); + setupWarningFlags(dict); + String[] cmdArray; String cmd = prefs.getOrExcept("recipe.c.combine.pattern"); try { @@ -1034,6 +1134,18 @@ public class Compiler implements MessageConsumer { execAsynchronously(cmdArray); } + void runActions(String recipeClass, PreferencesMap prefs) throws RunnerException, PreferencesMapException { + List patterns = new ArrayList(); + for (String key : prefs.keySet()) { + if (key.startsWith("recipe."+recipeClass) && key.endsWith(".pattern")) + patterns.add(key); + } + Collections.sort(patterns); + for (String recipe : patterns) { + runRecipe(recipe); + } + } + void runRecipe(String recipe) throws RunnerException, PreferencesMapException { PreferencesMap dict = new PreferencesMap(prefs); dict.put("ide_version", "" + BaseNoGui.REVISION); @@ -1047,6 +1159,32 @@ public class Compiler implements MessageConsumer { } execAsynchronously(cmdArray); } + + //7. Save the .hex file + void saveHex() throws RunnerException { + if (!prefs.containsKey("recipe.output.tmp_file") || !prefs.containsKey("recipe.output.save_file")) { + System.err.println(_("Warning: This core does not support exporting sketches. Please consider upgrading it or contacting its author")); + return; + } + + PreferencesMap dict = new PreferencesMap(prefs); + dict.put("ide_version", "" + BaseNoGui.REVISION); + + try { + String compiledSketch = prefs.getOrExcept("recipe.output.tmp_file"); + compiledSketch = StringReplacer.replaceFromMapping(compiledSketch, dict); + String copyOfCompiledSketch = prefs.getOrExcept("recipe.output.save_file"); + copyOfCompiledSketch = StringReplacer.replaceFromMapping(copyOfCompiledSketch, dict); + + File compiledSketchFile = new File(prefs.get("build.path"), compiledSketch); + File copyOfCompiledSketchFile = new File(sketch.getFolder(), copyOfCompiledSketch); + + FileUtils.copyFile(compiledSketchFile, copyOfCompiledSketchFile); + } catch (Exception e) { + throw new RunnerException(e); + } + } + private static String prepareIncludes(List includeFolders) { String res = ""; @@ -1113,12 +1251,12 @@ public class Compiler implements MessageConsumer { // 2. run preproc on that code using the sugg class name // to create a single .java file and write to buildpath + FileOutputStream outputStream = null; try { // Output file File streamFile = new File(buildPath, sketch.getName() + ".cpp"); - FileOutputStream outputStream = new FileOutputStream(streamFile); + outputStream = new FileOutputStream(streamFile); preprocessor.write(outputStream); - outputStream.close(); } catch (FileNotFoundException fnfe) { fnfe.printStackTrace(); String msg = _("Build folder disappeared or could not be written"); @@ -1133,15 +1271,32 @@ public class Compiler implements MessageConsumer { System.err.println(I18n.format(_("Uncaught exception type: {0}"), ex.getClass())); ex.printStackTrace(); throw new RunnerException(ex.toString()); + } finally { + if (outputStream != null) { + try { + outputStream.close(); + } catch (IOException e) { + //noop + } + } } // grab the imports from the code just preproc'd importedLibraries = new LibraryList(); + importedDuplicateHeaders = new ArrayList(); + importedDuplicateLibraries = new ArrayList(); for (String item : preprocessor.getExtraImports()) { - Library lib = BaseNoGui.importToLibraryTable.get(item); - if (lib != null && !importedLibraries.contains(lib)) { - importedLibraries.add(lib); + LibraryList list = BaseNoGui.importToLibraryTable.get(item); + if (list != null) { + UserLibrary lib = list.peekFirst(); + if (lib != null && !importedLibraries.contains(lib)) { + importedLibraries.add(lib); + if (list.size() > 1) { + importedDuplicateHeaders.add(item); + importedDuplicateLibraries.add(list); + } + } } } @@ -1173,6 +1328,8 @@ public class Compiler implements MessageConsumer { * List of library folders. */ private LibraryList importedLibraries; + private List importedDuplicateHeaders; + private List importedDuplicateLibraries; /** * Map an error from a set of processed .java files back to its location diff --git a/arduino-core/src/processing/app/debug/LegacyTargetBoard.java b/arduino-core/src/processing/app/debug/LegacyTargetBoard.java new file mode 100644 index 000000000..ff06ab29d --- /dev/null +++ b/arduino-core/src/processing/app/debug/LegacyTargetBoard.java @@ -0,0 +1,113 @@ +/* + TargetPackage - Represents a hardware package + Part of the Arduino project - http://www.arduino.cc/ + + Copyright (c) 2014 Cristian Maglie + + 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 static processing.app.I18n._; +import static processing.app.I18n.format; + +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +import processing.app.helpers.PreferencesMap; + +public class LegacyTargetBoard implements TargetBoard { + + private String id; + private PreferencesMap prefs; + private Map menuOptions = new LinkedHashMap(); + private TargetPlatform containerPlatform; + + /** + * Create a TargetBoard based on preferences passed as argument. + * + * @param _prefs + * @return + */ + public LegacyTargetBoard(String _id, PreferencesMap _prefs, + TargetPlatform parent) { + containerPlatform = parent; + id = _id; + prefs = new PreferencesMap(_prefs); + + // Setup sub-menus + PreferencesMap menus = prefs.firstLevelMap().get("menu"); + if (menus != null) + menuOptions = menus.firstLevelMap(); + + // Auto generate build.board if not set + if (!prefs.containsKey("build.board")) { + String board = containerPlatform.getId() + "_" + id; + board = board.toUpperCase(); + prefs.put("build.board", board); + System.out + .println(format(_("Board {0}:{1}:{2} doesn''t define a ''build.board'' preference. Auto-set to: {3}"), + containerPlatform.getContainerPackage().getId(), + containerPlatform.getId(), id, board)); + } + } + + @Override + public String getName() { + return prefs.get("name"); + } + + @Override + public String getId() { + return id; + } + + @Override + public PreferencesMap getPreferences() { + return prefs; + } + + @Override + public boolean hasMenu(String menuId) { + return menuOptions.containsKey(menuId); + } + + @Override + public PreferencesMap getMenuLabels(String menuId) { + return menuOptions.get(menuId).topLevelMap(); + } + + @Override + public String getMenuLabel(String menuId, String selectionId) { + return getMenuLabels(menuId).get(selectionId); + } + + @Override + public Set getMenuIds() { + return menuOptions.keySet(); + } + + @Override + public PreferencesMap getMenuPreferences(String menuId, String selectionId) { + return menuOptions.get(menuId).subTree(selectionId); + } + + @Override + public TargetPlatform getContainerPlatform() { + return containerPlatform; + } + +} diff --git a/arduino-core/src/processing/app/debug/LegacyTargetPackage.java b/arduino-core/src/processing/app/debug/LegacyTargetPackage.java new file mode 100644 index 000000000..42d6b0730 --- /dev/null +++ b/arduino-core/src/processing/app/debug/LegacyTargetPackage.java @@ -0,0 +1,89 @@ +/* + TargetPackage - Represents a hardware package + Part of the Arduino project - http://www.arduino.cc/ + + Copyright (c) 2011 Cristian Maglie + + 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 static processing.app.I18n._; +import static processing.app.helpers.filefilters.OnlyDirs.ONLY_DIRS; + +import java.io.File; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.Map; + +import processing.app.I18n; + +public class LegacyTargetPackage implements TargetPackage { + + private String id; + private Map platforms; + + public LegacyTargetPackage(String _id, File _folder) throws TargetPlatformException { + id = _id; + platforms = new LinkedHashMap(); + + File[] folders = _folder.listFiles(ONLY_DIRS); + if (folders == null) + return; + + for (File subFolder : folders) { + if (!subFolder.exists() || !subFolder.canRead()) + continue; + String arch = subFolder.getName(); + try { + TargetPlatform platform = new LegacyTargetPlatform(arch, subFolder, this); + platforms.put(arch, platform); + } catch (TargetPlatformException e) { + System.out.println(e.getMessage()); + } + } + + if (platforms.size() == 0) { + throw new TargetPlatformException(I18n + .format(_("No valid hardware definitions found in folder {0}."), + _folder.getName())); + } + } + + @Override + public Map getPlatforms() { + return platforms; + } + + @Override + public Collection platforms() { + return platforms.values(); + } + + @Override + public TargetPlatform get(String platform) { + return platforms.get(platform); + } + + @Override + public boolean hasPlatform(TargetPlatform platform) { + return platforms.containsKey(platform.getId()); + } + + @Override + public String getId() { + return id; + } +} diff --git a/arduino-core/src/processing/app/debug/LegacyTargetPlatform.java b/arduino-core/src/processing/app/debug/LegacyTargetPlatform.java new file mode 100644 index 000000000..b9cd2a89e --- /dev/null +++ b/arduino-core/src/processing/app/debug/LegacyTargetPlatform.java @@ -0,0 +1,241 @@ +/* + TargetPlatform - Represents a hardware platform + Part of the Arduino project - http://www.arduino.cc/ + + Copyright (c) 2009-2014 Arduino + + 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.BaseNoGui; +import processing.app.I18n; +import processing.app.helpers.PreferencesMap; + +import java.io.File; +import java.io.IOException; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +import static processing.app.I18n._; +import static processing.app.I18n.format; + +public class LegacyTargetPlatform implements TargetPlatform { + + private String id; + private File folder; + + private TargetPackage containerPackage; + protected PreferencesMap preferences = new PreferencesMap(); + + private Map boards = new LinkedHashMap(); + private TargetBoard defaultBoard; + + /** + * Contains preferences for every defined programmer + */ + private Map programmers = new LinkedHashMap(); + + /** + * Contains labels for top level menus + */ + private PreferencesMap customMenus = new PreferencesMap(); + + public LegacyTargetPlatform(String _name, File _folder, TargetPackage parent) + throws TargetPlatformException { + + id = _name; + folder = _folder; + containerPackage = parent; + + // If there is no boards.txt, this is not a valid 1.5 hardware folder + File boardsFile = new File(folder, "boards.txt"); + if (!boardsFile.exists() || !boardsFile.canRead()) + throw new TargetPlatformException( + format(_("Could not find boards.txt in {0}. Is it pre-1.5?"), + folder.getAbsolutePath())); + + // Load boards + try { + Map boardsPreferences = new PreferencesMap( + boardsFile).firstLevelMap(); + + // Create custom menus for this platform + PreferencesMap menus = boardsPreferences.get("menu"); + if (menus != null) + customMenus = menus.topLevelMap(); + boardsPreferences.remove("menu"); + + // Create boards + Set boardIds = boardsPreferences.keySet(); + for (String boardId : boardIds) { + PreferencesMap preferences = boardsPreferences.get(boardId); + TargetBoard board = new LegacyTargetBoard(boardId, preferences, this); + boards.put(boardId, board); + + // Pick the first board as default + if (defaultBoard == null) + defaultBoard = board; + } + } catch (IOException e) { + throw new TargetPlatformException(format(_("Error loading {0}"), + boardsFile.getAbsolutePath()), e); + } + + File platformsFile = new File(folder, "platform.txt"); + try { + if (platformsFile.exists() && platformsFile.canRead()) { + preferences.load(platformsFile); + } + } catch (IOException e) { + throw new TargetPlatformException( + format(_("Error loading {0}"), platformsFile.getAbsolutePath()), e); + } + + // Allow overriding values in platform.txt. This allows changing + // platform.txt (e.g. to use a system-wide toolchain), without + // having to modify platform.txt (which, when running from git, + // prevents files being marked as changed). + File localPlatformsFile = new File(folder, "platform.local.txt"); + try { + if (localPlatformsFile.exists() && localPlatformsFile.canRead()) { + preferences.load(localPlatformsFile); + } + } catch (IOException e) { + throw new TargetPlatformException( + format(_("Error loading {0}"), localPlatformsFile.getAbsolutePath()), e); + } + + if (!preferences.containsKey("rewriting") || !"disabled".equals(preferences.get("rewriting"))) { + try { + rewriteKeysOfOldPlatformsTxtAndWarnAboutIt(); + } catch (IOException e) { + throw new TargetPlatformException(e); + } + } + + File progFile = new File(folder, "programmers.txt"); + try { + if (progFile.exists() && progFile.canRead()) { + PreferencesMap prefs = new PreferencesMap(); + prefs.load(progFile); + programmers = prefs.firstLevelMap(); + } + } catch (IOException e) { + throw new TargetPlatformException(format(_("Error loading {0}"), + progFile.getAbsolutePath()), e); + } + } + + private void rewriteKeysOfOldPlatformsTxtAndWarnAboutIt() throws IOException { + File platformRewrite = new File(BaseNoGui.getHardwareFolder(), "platform.keys.rewrite.txt"); + PreferencesMap platformRewriteProps = new PreferencesMap(platformRewrite); + + PreferencesMap oldProps = platformRewriteProps.subTree("old"); + PreferencesMap newProps = platformRewriteProps.subTree("new"); + + String platformName = preferences.get("name"); + if (platformName == null) { + platformName = folder.getAbsolutePath(); + } + + for (Map.Entry entry : oldProps.entrySet()) { + String preferencesKey = entry.getKey().substring(entry.getKey().indexOf(".") + 1); + if (preferences.containsKey(preferencesKey) && entry.getValue().equals(preferences.get(preferencesKey))) { + System.err.println(I18n.format(_("Warning: platform.txt from core '{0}' contains deprecated {1}, automatically converted to {2}. Consider upgrading this core."), platformName, preferencesKey + "=" + entry.getValue(), preferencesKey + "=" + newProps.get(entry.getKey()))); + preferences.put(preferencesKey, newProps.get(entry.getKey())); + } + } + + PreferencesMap addedProps = platformRewriteProps.subTree("added"); + for (Map.Entry entry : addedProps.entrySet()) { + String keyToAdd = entry.getKey(); + String[] keyToAddParts = keyToAdd.split("\\."); + String keyToAddFirstLevel = keyToAddParts[0]; + String keyToAddSecondLevel = keyToAddParts[0] + "." + keyToAddParts[1]; + if (!preferences.subTree(keyToAddFirstLevel).isEmpty() && !preferences.subTree(keyToAddSecondLevel).isEmpty() && !preferences.containsKey(keyToAdd)) { + System.err.println(I18n.format(_("Warning: platform.txt from core '{0}' misses property {1}, automatically set to {2}. Consider upgrading this core."), platformName, keyToAdd, entry.getValue())); + preferences.put(keyToAdd, entry.getValue()); + } + } + } + + @Override + public String getId() { + return id; + } + + @Override + public File getFolder() { + return folder; + } + + @Override + public Map getBoards() { + return boards; + } + + @Override + public PreferencesMap getCustomMenus() { + return customMenus; + } + + @Override + public Set getCustomMenuIds() { + return customMenus.keySet(); + } + + @Override + public Map getProgrammers() { + return programmers; + } + + @Override + public PreferencesMap getProgrammer(String programmer) { + return getProgrammers().get(programmer); + } + + @Override + public PreferencesMap getTool(String tool) { + return getPreferences().subTree("tools").subTree(tool); + } + + @Override + public PreferencesMap getPreferences() { + return preferences; + } + + @Override + public TargetBoard getBoard(String boardId) { + if (boards.containsKey(boardId)) { + return boards.get(boardId); + } + return defaultBoard; + } + + @Override + public TargetPackage getContainerPackage() { + return containerPackage; + } + + @Override + public String toString() { + String res = "TargetPlatform: name=" + id + " boards={\n"; + for (String boardId : boards.keySet()) + res += " " + boardId + " = " + boards.get(boardId) + "\n"; + return res + "}"; + } +} diff --git a/arduino-core/src/processing/app/debug/TargetBoard.java b/arduino-core/src/processing/app/debug/TargetBoard.java index 721b69613..5dae86906 100644 --- a/arduino-core/src/processing/app/debug/TargetBoard.java +++ b/arduino-core/src/processing/app/debug/TargetBoard.java @@ -1,76 +1,51 @@ +/* + TargetBoard - Represents a hardware board + Part of the Arduino project - http://www.arduino.cc/ + + Copyright (c) 2014 Cristian Maglie + + 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 static processing.app.I18n._; -import static processing.app.I18n.format; - -import java.util.LinkedHashMap; -import java.util.Map; import java.util.Set; import processing.app.helpers.PreferencesMap; -public class TargetBoard { - - private String id; - private PreferencesMap prefs; - private Map menuOptions = new LinkedHashMap(); - private TargetPlatform containerPlatform; - - /** - * Create a TargetBoard based on preferences passed as argument. - * - * @param _prefs - * @return - */ - public TargetBoard(String _id, PreferencesMap _prefs, TargetPlatform parent) { - containerPlatform = parent; - id = _id; - prefs = new PreferencesMap(_prefs); - - // Setup sub-menus - PreferencesMap menus = prefs.firstLevelMap().get("menu"); - if (menus != null) - menuOptions = menus.firstLevelMap(); - - // Auto generate build.board if not set - if (!prefs.containsKey("build.board")) { - String board = containerPlatform.getId() + "_" + id; - board = board.toUpperCase(); - prefs.put("build.board", board); - System.out - .println(format( - _("Board {0}:{1}:{2} doesn''t define a ''build.board'' preference. Auto-set to: {3}"), - containerPlatform.getContainerPackage().getId(), - containerPlatform.getId(), id, board)); - } - } +public interface TargetBoard { /** * Get the name of the board. * * @return */ - public String getName() { - return prefs.get("name"); - } + public String getName(); /** * Get the identifier of the board * * @return */ - public String getId() { - return id; - } + public String getId(); /** - * Get the full preferences map of the board with a given identifier + * Get the full preferences map of the board * * @return */ - public PreferencesMap getPreferences() { - return prefs; - } + public PreferencesMap getPreferences(); /** * Check if the board has a sub menu. @@ -79,9 +54,7 @@ public class TargetBoard { * The menu ID to check * @return */ - public boolean hasMenu(String menuId) { - return menuOptions.containsKey(menuId); - } + public boolean hasMenu(String menuId); /** * Returns the options available on a specific menu @@ -90,9 +63,7 @@ public class TargetBoard { * The menu ID * @return */ - public PreferencesMap getMenuLabels(String menuId) { - return menuOptions.get(menuId).topLevelMap(); - } + public PreferencesMap getMenuLabels(String menuId); /** * Returns the label of the specified option in the specified menu @@ -103,13 +74,9 @@ public class TargetBoard { * The option ID * @return */ - public String getMenuLabel(String menuId, String selectionId) { - return getMenuLabels(menuId).get(selectionId); - } + public String getMenuLabel(String menuId, String selectionId); - public Set getMenuIds() { - return menuOptions.keySet(); - } + public Set getMenuIds(); /** * Returns the configuration parameters to override (as a PreferenceMap) when @@ -121,12 +88,8 @@ public class TargetBoard { * The option ID * @return */ - public PreferencesMap getMenuPreferences(String menuId, String selectionId) { - return menuOptions.get(menuId).subTree(selectionId); - } + public PreferencesMap getMenuPreferences(String menuId, String selectionId); - public TargetPlatform getContainerPlatform() { - return containerPlatform; - } + public TargetPlatform getContainerPlatform(); } diff --git a/arduino-core/src/processing/app/debug/TargetPackage.java b/arduino-core/src/processing/app/debug/TargetPackage.java index dce91d178..2df6880b0 100644 --- a/arduino-core/src/processing/app/debug/TargetPackage.java +++ b/arduino-core/src/processing/app/debug/TargetPackage.java @@ -1,9 +1,8 @@ -/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* TargetPackage - Represents a hardware package Part of the Arduino project - http://www.arduino.cc/ - Copyright (c) 2011 Cristian Maglie + Copyright (c) 2014 Cristian Maglie 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 @@ -21,61 +20,18 @@ */ package processing.app.debug; -import static processing.app.I18n._; - -import java.io.File; import java.util.Collection; -import java.util.LinkedHashMap; import java.util.Map; -import processing.app.I18n; -import processing.app.helpers.filefilters.OnlyDirs; +public interface TargetPackage { -public class TargetPackage { + String getId(); - private String id; + Map getPlatforms(); - Map platforms = new LinkedHashMap(); + Collection platforms(); - public TargetPackage(String _id, File _folder) throws TargetPlatformException { - id = _id; + TargetPlatform get(String platform); - File[] folders = _folder.listFiles(new OnlyDirs()); - if (folders == null) - return; - - for (File subFolder : folders) { - if (!subFolder.exists() || !subFolder.canRead()) - continue; - String arch = subFolder.getName(); - try { - TargetPlatform platform = new TargetPlatform(arch, subFolder, this); - platforms.put(arch, platform); - } catch (TargetPlatformException e) { - System.out.println(e.getMessage()); - } - } - - if (platforms.size() == 0) { - throw new TargetPlatformException(I18n - .format(_("No valid hardware definitions found in folder {0}."), - _folder.getName())); - } - } - - public Map getPlatforms() { - return platforms; - } - - public Collection platforms() { - return platforms.values(); - } - - public TargetPlatform get(String platform) { - return platforms.get(platform); - } - - public String getId() { - return id; - } + boolean hasPlatform(TargetPlatform platform); } diff --git a/arduino-core/src/processing/app/debug/TargetPlatform.java b/arduino-core/src/processing/app/debug/TargetPlatform.java index 611784618..4b13cf87a 100644 --- a/arduino-core/src/processing/app/debug/TargetPlatform.java +++ b/arduino-core/src/processing/app/debug/TargetPlatform.java @@ -1,9 +1,8 @@ -/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* TargetPlatform - Represents a hardware platform Part of the Arduino project - http://www.arduino.cc/ - Copyright (c) 2009 David A. Mellis + Copyright (c) 2014 Arduino 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 @@ -21,174 +20,78 @@ */ package processing.app.debug; -import static processing.app.I18n._; -import static processing.app.I18n.format; - import java.io.File; -import java.io.IOException; -import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; import processing.app.helpers.PreferencesMap; -public class TargetPlatform { +public interface TargetPlatform { - private String id; - private File folder; - private TargetPackage containerPackage; + public String getId(); + + public File getFolder(); /** - * Contains preferences for every defined board + * Get TargetBoards under this TargetPlatform into a Map that maps the board + * id with the corresponding TargetBoard + * + * @return a Map */ - private Map boards = new LinkedHashMap(); - private TargetBoard defaultBoard; + public Map getBoards(); + + public PreferencesMap getCustomMenus(); /** - * Contains preferences for every defined programmer + * Return ids for top level menus + * + * @return a Set with the ids of the top level custom menus */ - private Map programmers = new LinkedHashMap(); + public Set getCustomMenuIds(); /** - * Contains preferences for platform + * Get preferences for all programmers + * + * @return */ - private PreferencesMap preferences = new PreferencesMap(); + public Map getProgrammers(); /** - * Contains labels for top level menus + * Get preferences for a specific programmer + * + * @param programmer + * @return */ - private PreferencesMap customMenus = new PreferencesMap(); + public PreferencesMap getProgrammer(String programmer); - public TargetPlatform(String _name, File _folder, TargetPackage parent) - throws TargetPlatformException { + /** + * Get preferences for a specific tool + * + * @param tool + * @return + */ + public PreferencesMap getTool(String tool); - id = _name; - folder = _folder; - containerPackage = parent; + /** + * Return TargetPlatform preferences + * + * @return + */ + public PreferencesMap getPreferences(); - // If there is no boards.txt, this is not a valid 1.5 hardware folder - File boardsFile = new File(folder, "boards.txt"); - if (!boardsFile.exists() || !boardsFile.canRead()) - throw new TargetPlatformException( - format(_("Could not find boards.txt in {0}. Is it pre-1.5?"), - folder.getAbsolutePath())); + /** + * Get a target board + * + * @param boardId + * @return + */ + public TargetBoard getBoard(String boardId); - // Load boards - try { - Map boardsPreferences = new PreferencesMap( - boardsFile).firstLevelMap(); + /** + * Get the TargetPackage that contains this TargetPlatform + * + * @return + */ + public TargetPackage getContainerPackage(); - // Create custom menus for this platform - PreferencesMap menus = boardsPreferences.get("menu"); - if (menus != null) - customMenus = menus.topLevelMap(); - boardsPreferences.remove("menu"); - - // Create boards - Set boardIds = boardsPreferences.keySet(); - for (String boardId : boardIds) { - PreferencesMap preferences = boardsPreferences.get(boardId); - TargetBoard board = new TargetBoard(boardId, preferences, this); - boards.put(boardId, board); - - // Pick the first board as default - if (defaultBoard == null) - defaultBoard = board; - } - } catch (IOException e) { - throw new TargetPlatformException(format(_("Error loading {0}"), - boardsFile.getAbsolutePath()), e); - } - - File platformsFile = new File(folder, "platform.txt"); - try { - if (platformsFile.exists() && platformsFile.canRead()) { - preferences.load(platformsFile); - } - } catch (IOException e) { - throw new TargetPlatformException( - format(_("Error loading {0}"), platformsFile.getAbsolutePath()), e); - } - - // Allow overriding values in platform.txt. This allows changing - // platform.txt (e.g. to use a system-wide toolchain), without - // having to modify platform.txt (which, when running from git, - // prevents files being marked as changed). - File localPlatformsFile = new File(folder, "platform.local.txt"); - try { - if (localPlatformsFile.exists() && localPlatformsFile.canRead()) { - preferences.load(localPlatformsFile); - } - } catch (IOException e) { - throw new TargetPlatformException( - format(_("Error loading {0}"), localPlatformsFile.getAbsolutePath()), e); - } - - File progFile = new File(folder, "programmers.txt"); - try { - if (progFile.exists() && progFile.canRead()) { - PreferencesMap prefs = new PreferencesMap(); - prefs.load(progFile); - programmers = prefs.firstLevelMap(); - } - } catch (IOException e) { - throw new TargetPlatformException(format(_("Error loading {0}"), progFile - .getAbsolutePath()), e); - } - } - - public String getId() { - return id; - } - - public File getFolder() { - return folder; - } - - public Map getBoards() { - return boards; - } - - public PreferencesMap getCustomMenus() { - return customMenus; - } - - public Set getCustomMenuIds() { - return customMenus.keySet(); - } - - public Map getProgrammers() { - return programmers; - } - - public PreferencesMap getProgrammer(String programmer) { - return getProgrammers().get(programmer); - } - - public PreferencesMap getTool(String tool) { - return getPreferences().subTree("tools").subTree(tool); - } - - public PreferencesMap getPreferences() { - return preferences; - } - - public TargetBoard getBoard(String boardId) { - if (boards.containsKey(boardId)) { - return boards.get(boardId); - } - return defaultBoard; - } - - public TargetPackage getContainerPackage() { - return containerPackage; - } - - @Override - public String toString() { - String res = "TargetPlatform: name=" + id + " boards={\n"; - for (String boardId : boards.keySet()) - res += " " + boardId + " = " + boards.get(boardId) + "\n"; - return res + "}"; - } } diff --git a/arduino-core/src/processing/app/helpers/CommandlineParser.java b/arduino-core/src/processing/app/helpers/CommandlineParser.java index 2fc43b103..2e66e6361 100644 --- a/arduino-core/src/processing/app/helpers/CommandlineParser.java +++ b/arduino-core/src/processing/app/helpers/CommandlineParser.java @@ -1,13 +1,5 @@ package processing.app.helpers; -import static processing.app.I18n._; - -import java.io.File; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - import processing.app.BaseNoGui; import processing.app.I18n; import processing.app.PreferencesData; @@ -16,34 +8,59 @@ import processing.app.debug.TargetPackage; import processing.app.debug.TargetPlatform; import processing.app.legacy.PApplet; +import java.io.File; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import static processing.app.I18n._; + public class CommandlineParser { - protected static enum ACTION { GUI, NOOP, VERIFY, UPLOAD, GET_PREF }; + private enum ACTION { + GUI, NOOP, VERIFY("--verify"), UPLOAD("--upload"), GET_PREF("--get-pref"), INSTALL_BOARD("--install-boards"), INSTALL_LIBRARY("--install-library"); + + private final String value; + + ACTION() { + this.value = null; + } + + ACTION(String value) { + this.value = value; + } + } private ACTION action = ACTION.GUI; private boolean doVerboseBuild = false; private boolean doVerboseUpload = false; private boolean doUseProgrammer = false; + private boolean preserveTempFiles; private boolean noUploadPort = false; private boolean forceSavePrefs = false; - private String getPref = null; + private String getPref; + private String boardToInstall; + private String libraryToInstall; private List filenames = new LinkedList(); public static CommandlineParser newCommandlineParser(String[] args) { return new CommandlineParser(args); } - + private CommandlineParser(String[] args) { parseArguments(args); checkAction(); } - + private void parseArguments(String[] args) { // Map of possible actions and corresponding options final Map actions = new HashMap(); actions.put("--verify", ACTION.VERIFY); actions.put("--upload", ACTION.UPLOAD); actions.put("--get-pref", ACTION.GET_PREF); + actions.put("--install-boards", ACTION.INSTALL_BOARD); + actions.put("--install-library", ACTION.INSTALL_LIBRARY); // Check if any files were passed in on the command line for (int i = 0; i < args.length; i++) { @@ -56,10 +73,25 @@ public class CommandlineParser { } if (a == ACTION.GET_PREF) { i++; - if (i >= args.length) - BaseNoGui.showError(null, _("Argument required for --get-pref"), 3); + if (i >= args.length) { + BaseNoGui.showError(null, I18n.format(_("Argument required for {0}"), a.value), 3); + } getPref = args[i]; } + if (a == ACTION.INSTALL_BOARD) { + i++; + if (i >= args.length) { + BaseNoGui.showError(null, I18n.format(_("Argument required for {0}"), a.value), 3); + } + boardToInstall = args[i]; + } + if (a == ACTION.INSTALL_LIBRARY) { + i++; + if (i >= args.length) { + BaseNoGui.showError(null, I18n.format(_("Argument required for {0}"), a.value), 3); + } + libraryToInstall = args[i]; + } action = a; continue; } @@ -74,6 +106,12 @@ public class CommandlineParser { action = ACTION.NOOP; continue; } + if (args[i].equals("--preserve-temp-files")) { + preserveTempFiles = true; + if (action == ACTION.GUI) + action = ACTION.NOOP; + continue; + } if (args[i].equals("--verbose-build")) { doVerboseBuild = true; if (action == ACTION.GUI) @@ -164,7 +202,7 @@ public class CommandlineParser { filenames.add(args[i]); } } - + private void checkAction() { if ((action == ACTION.UPLOAD || action == ACTION.VERIFY) && filenames.size() != 1) BaseNoGui.showError(null, _("Must specify exactly one sketch file"), 3); @@ -179,7 +217,7 @@ public class CommandlineParser { private void processBoardArgument(String selectBoard) { // No board selected? Nothing to do if (selectBoard == null) - return; + return; String[] split = selectBoard.split(":", 4); @@ -251,27 +289,27 @@ public class CommandlineParser { public List getFilenames() { return filenames; } - + public boolean isGetPrefMode() { return action == ACTION.GET_PREF; } - + public boolean isGuiMode() { return action == ACTION.GUI; } - + public boolean isNoOpMode() { return action == ACTION.NOOP; } - + public boolean isUploadMode() { return action == ACTION.UPLOAD; } - + public boolean isVerifyMode() { return action == ACTION.VERIFY; } - + public boolean isVerifyOrUploadMode() { return isVerifyMode() || isUploadMode(); } @@ -284,4 +322,23 @@ public class CommandlineParser { return noUploadPort; } + public boolean isInstallBoard() { + return action == ACTION.INSTALL_BOARD; + } + + public boolean isInstallLibrary() { + return action == ACTION.INSTALL_LIBRARY; + } + + public String getBoardToInstall() { + return this.boardToInstall; + } + + public String getLibraryToInstall() { + return libraryToInstall; + } + + public boolean isPreserveTempFiles() { + return preserveTempFiles; + } } diff --git a/arduino-core/src/processing/app/helpers/FileUtils.java b/arduino-core/src/processing/app/helpers/FileUtils.java index 39e49217c..186141cf5 100644 --- a/arduino-core/src/processing/app/helpers/FileUtils.java +++ b/arduino-core/src/processing/app/helpers/FileUtils.java @@ -73,17 +73,28 @@ public class FileUtils { } public static void recursiveDelete(File file) { - if (file == null) + if (file == null) { return; + } if (file.isDirectory()) { - for (File current : file.listFiles()) + File[] files = file.listFiles(); + if (files == null) { + return; + } + for (File current : files) { recursiveDelete(current); + } } file.delete(); } public static File createTempFolder() throws IOException { - File tmpFolder = new File(System.getProperty("java.io.tmpdir"), "arduino_" + new Random().nextInt(1000000)); + return createTempFolderIn(new File(System.getProperty("java.io.tmpdir"))); + } + + public static File createTempFolderIn(File parent) throws IOException { + File tmpFolder = new File(parent, "arduino_" + + new Random().nextInt(1000000)); if (!tmpFolder.mkdir()) { throw new IOException("Unable to create temp folder " + tmpFolder); } @@ -249,5 +260,21 @@ public class FileUtils { return result; } + public static File newFile(File parent, String... parts) { + File result = parent; + for (String part : parts) { + result = new File(result, part); + } + + return result; + } + + public static boolean deleteIfExists(File file) { + if (file == null) { + return true; + } + + return file.delete(); + } } diff --git a/arduino-core/src/processing/app/helpers/NetUtils.java b/arduino-core/src/processing/app/helpers/NetUtils.java index 67201bf3d..17dc52c86 100644 --- a/arduino-core/src/processing/app/helpers/NetUtils.java +++ b/arduino-core/src/processing/app/helpers/NetUtils.java @@ -11,7 +11,7 @@ public abstract class NetUtils { private static boolean isReachableByEcho(InetAddress address) { try { - return address.isReachable(100); + return address.isReachable(300); } catch (IOException e) { return false; } @@ -38,7 +38,7 @@ public abstract class NetUtils { Socket socket = null; try { socket = new Socket(); - socket.connect(new InetSocketAddress(address, port), 300); + socket.connect(new InetSocketAddress(address, port), 1000); return true; } catch (IOException e) { return false; diff --git a/arduino-core/src/processing/app/helpers/PreferencesMap.java b/arduino-core/src/processing/app/helpers/PreferencesMap.java index 09a095447..185e1bee4 100644 --- a/arduino-core/src/processing/app/helpers/PreferencesMap.java +++ b/arduino-core/src/processing/app/helpers/PreferencesMap.java @@ -21,18 +21,14 @@ */ package processing.app.helpers; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; +import processing.app.legacy.PApplet; + +import java.io.*; import java.util.LinkedHashMap; import java.util.Map; import java.util.SortedSet; import java.util.TreeSet; -import processing.app.legacy.PApplet; - @SuppressWarnings("serial") public class PreferencesMap extends LinkedHashMap { @@ -71,7 +67,15 @@ public class PreferencesMap extends LinkedHashMap { * @throws IOException */ public void load(File file) throws IOException { - load(new FileInputStream(file)); + FileInputStream fileInputStream = null; + try { + fileInputStream = new FileInputStream(file); + load(fileInputStream); + } finally { + if (fileInputStream != null) { + fileInputStream.close(); + } + } } protected String processPlatformSuffix(String key, String suffix, boolean isCurrentPlatform) { @@ -311,7 +315,7 @@ public class PreferencesMap extends LinkedHashMap { * insensitive compared), false in any other case */ public boolean getBoolean(String key) { - return new Boolean(get(key)); + return Boolean.valueOf(get(key)); } /** diff --git a/arduino-core/src/processing/app/helpers/StringUtils.java b/arduino-core/src/processing/app/helpers/StringUtils.java index ea623d901..fb60df330 100644 --- a/arduino-core/src/processing/app/helpers/StringUtils.java +++ b/arduino-core/src/processing/app/helpers/StringUtils.java @@ -26,4 +26,18 @@ public class StringUtils { String regex = pattern.replace("?", ".?").replace("*", ".*?"); return input.matches(regex); } + + /** + * Returns the string without trailing whitespace characters + * + * @param s + * @return + */ + public static String rtrim(String s) { + int i = s.length() - 1; + while (i >= 0 && Character.isWhitespace(s.charAt(i))) { + i--; + } + return s.substring(0, i + 1); + } } diff --git a/arduino-core/src/processing/app/helpers/filefilters/OnlyDirs.java b/arduino-core/src/processing/app/helpers/filefilters/OnlyDirs.java index 46f407248..0cbe1cc7c 100644 --- a/arduino-core/src/processing/app/helpers/filefilters/OnlyDirs.java +++ b/arduino-core/src/processing/app/helpers/filefilters/OnlyDirs.java @@ -32,11 +32,17 @@ import java.io.FilenameFilter; */ public class OnlyDirs implements FilenameFilter { - public boolean accept(File dir, String name) { - if (name.charAt(0) == '.') - return false; - if (name.equals("CVS")) - return false; - return new File(dir, name).isDirectory(); - } + public boolean accept(File dir, String name) { + if (name.charAt(0) == '.') + return false; + if (name.equals("CVS")) + return false; + return new File(dir, name).isDirectory(); + } + + /** + * An handy pre-instantiated object + */ + public static final OnlyDirs ONLY_DIRS = new OnlyDirs(); + } diff --git a/arduino-core/src/processing/app/helpers/filefilters/OnlyFilesWithExtension.java b/arduino-core/src/processing/app/helpers/filefilters/OnlyFilesWithExtension.java index d57599942..c13adcbcf 100644 --- a/arduino-core/src/processing/app/helpers/filefilters/OnlyFilesWithExtension.java +++ b/arduino-core/src/processing/app/helpers/filefilters/OnlyFilesWithExtension.java @@ -29,13 +29,15 @@ public class OnlyFilesWithExtension implements FilenameFilter { String extensions[]; public OnlyFilesWithExtension(String... ext) { - extensions = ext; + this.extensions = ext; } public boolean accept(File dir, String name) { - for (String ext : extensions) - if (name.endsWith(ext)) + for (String ext : extensions) { + if (name.endsWith(ext)) { return true; + } + } return false; } diff --git a/arduino-core/src/processing/app/legacy/PApplet.java b/arduino-core/src/processing/app/legacy/PApplet.java index c444a3b2f..e89955263 100644 --- a/arduino-core/src/processing/app/legacy/PApplet.java +++ b/arduino-core/src/processing/app/legacy/PApplet.java @@ -1,16 +1,6 @@ package processing.app.legacy; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; -import java.io.UnsupportedEncodingException; +import java.io.*; import java.text.NumberFormat; import java.util.ArrayList; import java.util.StringTokenizer; @@ -276,15 +266,26 @@ public class PApplet { } static public String[] loadStrings(File file) { - InputStream is = createInput(file); - if (is != null) return loadStrings(is); - return null; + InputStream is = null; + try { + is = createInput(file); + if (is != null) return loadStrings(is); + return null; + } finally { + if (is != null) { + try { + is.close(); + } catch (IOException e) { + // noop + } + } + } } static public String[] loadStrings(InputStream input) { + BufferedReader reader = null; try { - BufferedReader reader = - new BufferedReader(new InputStreamReader(input, "UTF-8")); + reader = new BufferedReader(new InputStreamReader(input, "UTF-8")); String lines[] = new String[100]; int lineCount = 0; @@ -297,7 +298,6 @@ public class PApplet { } lines[lineCount++] = line; } - reader.close(); if (lineCount == lines.length) { return lines; @@ -311,6 +311,15 @@ public class PApplet { } catch (IOException e) { e.printStackTrace(); //throw new RuntimeException("Error inside loadStrings()"); + } finally { + if (reader != null) { + try { + reader.close(); + } catch (IOException e) { + //ignore + } + } + } return null; } @@ -321,14 +330,29 @@ public class PApplet { static public void saveStrings(File file, String strings[]) { - saveStrings(createOutput(file), strings); + OutputStream outputStream = null; + try { + outputStream = createOutput(file); + saveStrings(outputStream, strings); + } finally { + if (outputStream != null) { + try { + outputStream.close(); + } catch (IOException e) { + //noop + } + } + } } static public void saveStrings(OutputStream output, String strings[]) { PrintWriter writer = createWriter(output); - for (int i = 0; i < strings.length; i++) { - writer.println(strings[i]); + if (writer == null) { + return; + } + for (String string : strings) { + writer.println(string); } writer.flush(); writer.close(); diff --git a/arduino-core/src/processing/app/linux/GTKLookAndFeelFixer.java b/arduino-core/src/processing/app/linux/GTKLookAndFeelFixer.java new file mode 100644 index 000000000..9cc91c225 --- /dev/null +++ b/arduino-core/src/processing/app/linux/GTKLookAndFeelFixer.java @@ -0,0 +1,151 @@ +/* + * This file is part of Arduino. + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + * + * Copyright 2015 Arduino LLC (http://www.arduino.cc/) + */ + +package processing.app.linux; + +import javax.swing.*; +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +public class GTKLookAndFeelFixer { + + /* + * All functions of this class courtesy of Klaus Reimer + * https://www.ailis.de/~k/archives/67-Workaround-for-borderless-Java-Swing-menus-on-Linux.html + */ + + /* + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * 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 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. + * + * For more information, please refer to + */ + + /** + * Swing menus are looking pretty bad on Linux when the GTK LaF is used (See + * bug #6925412). It will most likely never be fixed anytime soon so this + * method provides a workaround for it. It uses reflection to change the GTK + * style objects of Swing so popup menu borders have a minimum thickness of + * 1 and menu separators have a minimum vertical thickness of 1. + */ + public static void installGtkPopupBugWorkaround() { + // Get current look-and-feel implementation class + LookAndFeel laf = UIManager.getLookAndFeel(); + Class lafClass = laf.getClass(); + + // Do nothing when not using the problematic LaF + if (!lafClass.getName().equals("com.sun.java.swing.plaf.gtk.GTKLookAndFeel")) { + return; + } + + // We do reflection from here on. Failure is silently ignored. The + // workaround is simply not installed when something goes wrong here + try { + // Access the GTK style factory + Field field = lafClass.getDeclaredField("styleFactory"); + boolean accessible = field.isAccessible(); + field.setAccessible(true); + Object styleFactory = field.get(laf); + field.setAccessible(accessible); + + // Fix the horizontal and vertical thickness of popup menu style + Object style = getGtkStyle(styleFactory, new JPopupMenu(), "POPUP_MENU"); + fixGtkThickness(style, "yThickness"); + fixGtkThickness(style, "xThickness"); + + // Fix the vertical thickness of the popup menu separator style + style = getGtkStyle(styleFactory, new JSeparator(), "POPUP_MENU_SEPARATOR"); + fixGtkThickness(style, "yThickness"); + } catch (Exception e) { + // Silently ignored. Workaround can't be applied. + } + } + + /** + * Called internally by installGtkPopupBugWorkaround to fix the thickness + * of a GTK style field by setting it to a minimum value of 1. + * + * @param style The GTK style object. + * @param fieldName The field name. + * @throws Exception When reflection fails. + */ + private static void fixGtkThickness(Object style, String fieldName) throws Exception { + Field field = style.getClass().getDeclaredField(fieldName); + boolean accessible = field.isAccessible(); + field.setAccessible(true); + field.setInt(style, Math.max(1, field.getInt(style))); + field.setAccessible(accessible); + } + + /** + * Called internally by installGtkPopupBugWorkaround. Returns a specific + * GTK style object. + * + * @param styleFactory The GTK style factory. + * @param component The target component of the style. + * @param regionName The name of the target region of the style. + * @return The GTK style. + * @throws Exception When reflection fails. + */ + private static Object getGtkStyle(Object styleFactory, JComponent component, String regionName) throws Exception { + // Create the region object + Class regionClass = Class.forName("javax.swing.plaf.synth.Region"); + Field field = regionClass.getField(regionName); + Object region = field.get(regionClass); + + // Get and return the style + Class styleFactoryClass = styleFactory.getClass(); + Method method = styleFactoryClass.getMethod("getStyle", JComponent.class, regionClass); + boolean accessible = method.isAccessible(); + method.setAccessible(true); + Object style = method.invoke(styleFactory, component, region); + method.setAccessible(accessible); + return style; + } +} diff --git a/arduino-core/src/processing/app/linux/Platform.java b/arduino-core/src/processing/app/linux/Platform.java index 57af15d15..ed91ea0a7 100644 --- a/arduino-core/src/processing/app/linux/Platform.java +++ b/arduino-core/src/processing/app/linux/Platform.java @@ -26,10 +26,12 @@ import org.apache.commons.exec.CommandLine; import org.apache.commons.exec.Executor; import processing.app.PreferencesData; import processing.app.debug.TargetPackage; -import processing.app.tools.ExternalProcessExecutor; import processing.app.legacy.PConstants; +import processing.app.tools.CollectStdOutExecutor; -import java.io.*; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; import java.util.Map; @@ -42,17 +44,7 @@ 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"); + GTKLookAndFeelFixer.installGtkPopupBugWorkaround(); } @@ -130,8 +122,9 @@ public class Platform extends processing.app.Platform { @Override public Map resolveDeviceAttachedTo(String serial, Map packages, String devicesListOutput) { + assert packages != null; ByteArrayOutputStream baos = new ByteArrayOutputStream(); - Executor executor = new ExternalProcessExecutor(baos); + Executor executor = new CollectStdOutExecutor(baos); try { CommandLine toDevicePath = CommandLine.parse("udevadm info -q path -n " + serial); diff --git a/arduino-core/src/processing/app/macosx/Platform.java b/arduino-core/src/processing/app/macosx/Platform.java index 433c7b9e7..7dc206635 100644 --- a/arduino-core/src/processing/app/macosx/Platform.java +++ b/arduino-core/src/processing/app/macosx/Platform.java @@ -26,12 +26,12 @@ import cc.arduino.packages.BoardPort; import com.apple.eio.FileManager; import org.apache.commons.exec.CommandLine; import org.apache.commons.exec.Executor; +import org.apache.commons.lang3.StringUtils; import processing.app.debug.TargetPackage; -import processing.app.tools.ExternalProcessExecutor; import processing.app.legacy.PApplet; import processing.app.legacy.PConstants; +import processing.app.tools.CollectStdOutExecutor; -import javax.swing.*; import java.awt.*; import java.io.*; import java.lang.reflect.Method; @@ -45,12 +45,9 @@ import java.util.List; */ public class Platform extends processing.app.Platform { + private String osArch; + 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 Platform() { @@ -59,35 +56,18 @@ public class Platform extends processing.app.Platform { Toolkit.getDefaultToolkit(); } - public void init() { + public void init() throws IOException { System.setProperty("apple.laf.useScreenMenuBar", "true"); - /* - 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 + ")"); + discoverRealOsArch(); + } - } 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(); - } - */ + private void discoverRealOsArch() throws IOException { + CommandLine uname = CommandLine.parse("uname -m"); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + CollectStdOutExecutor executor = new CollectStdOutExecutor(baos); + executor.execute(uname); + osArch = StringUtils.trim(new String(baos.toByteArray())); } @@ -115,7 +95,7 @@ public class Platform extends processing.app.Platform { public void openURL(String url) throws Exception { if (PApplet.javaVersion < 1.6f) { - if (url.startsWith("http://")) { + if (url.startsWith("http")) { // formerly com.apple.eio.FileManager.openURL(url); // but due to deprecation, instead loading dynamically try { @@ -139,7 +119,7 @@ public class Platform extends processing.app.Platform { // for Java 1.6, replacing with java.awt.Desktop.browse() // and java.awt.Desktop.open() - if (url.startsWith("http://")) { // browse to a location + if (url.startsWith("http")) { // browse to a location Method browseMethod = desktopClass.getMethod("browse", new Class[] { URI.class }); browseMethod.invoke(desktop, new Object[] { new URI(url) }); @@ -211,6 +191,7 @@ public class Platform extends processing.app.Platform { @Override public Map resolveDeviceAttachedTo(String serial, Map packages, String devicesListOutput) { + assert packages != null; if (devicesListOutput == null) { return super.resolveDeviceAttachedTo(serial, packages, devicesListOutput); } @@ -231,7 +212,7 @@ public class Platform extends processing.app.Platform { @Override public String preListAllCandidateDevices() { ByteArrayOutputStream baos = new ByteArrayOutputStream(); - Executor executor = new ExternalProcessExecutor(baos); + Executor executor = new CollectStdOutExecutor(baos); try { CommandLine toDevicePath = CommandLine.parse("/usr/sbin/system_profiler SPUSBDataType"); @@ -250,11 +231,16 @@ public class Platform extends processing.app.Platform { List filteredPorts = new LinkedList(); for (BoardPort port : ports) { - if (!port.getAddress().startsWith("/dev/cu.")) { + if (!port.getAddress().startsWith("/dev/tty.")) { filteredPorts.add(port); } } return filteredPorts; } + + @Override + public String getOsArch() { + return osArch; + } } diff --git a/arduino-core/src/processing/app/packages/LegacyUserLibrary.java b/arduino-core/src/processing/app/packages/LegacyUserLibrary.java new file mode 100644 index 000000000..b98aeb621 --- /dev/null +++ b/arduino-core/src/processing/app/packages/LegacyUserLibrary.java @@ -0,0 +1,126 @@ +/* + * This file is part of Arduino. + * + * Copyright 2014 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ +package processing.app.packages; + +import java.io.File; +import java.util.Arrays; +import java.util.List; + +import cc.arduino.contributions.libraries.ContributedLibraryReference; + +public class LegacyUserLibrary extends UserLibrary { + + private String name; + + public static LegacyUserLibrary create(File libFolder) { + // construct an old style library + LegacyUserLibrary res = new LegacyUserLibrary(); + res.setInstalledFolder(libFolder); + res.setInstalled(true); + res.layout = LibraryLayout.FLAT; + res.name = libFolder.getName(); + return res; + } + + @Override + public String getName() { + return name; + } + + @Override + public List getArchitectures() { + return Arrays.asList("*"); + } + + @Override + public String getAuthor() { + return null; + } + + @Override + public String getParagraph() { + return null; + } + + @Override + public String getSentence() { + return null; + } + + @Override + public String getWebsite() { + return null; + } + + @Override + public String getCategory() { + return "Uncategorized"; + } + + @Override + public String getLicense() { + return null; + } + + @Override + public String getVersion() { + return null; + } + + @Override + public String getMaintainer() { + return null; + } + + @Override + public String getChecksum() { + return null; + } + + @Override + public long getSize() { + return 0; + } + + @Override + public String getUrl() { + return null; + } + + @Override + public List getRequires() { + return null; + } + + @Override + public String toString() { + return "LegacyLibrary:" + name + "\n"; + } + +} diff --git a/arduino-core/src/processing/app/packages/LibraryList.java b/arduino-core/src/processing/app/packages/LibraryList.java index 343ff4bde..d4d504cea 100644 --- a/arduino-core/src/processing/app/packages/LibraryList.java +++ b/arduino-core/src/processing/app/packages/LibraryList.java @@ -1,14 +1,42 @@ +/* + * This file is part of Arduino. + * + * Copyright 2014 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ package processing.app.packages; import java.io.File; -import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; +import java.util.LinkedList; +import java.util.List; import processing.app.helpers.FileUtils; @SuppressWarnings("serial") -public class LibraryList extends ArrayList { +public class LibraryList extends LinkedList { public LibraryList(LibraryList libs) { super(libs); @@ -18,53 +46,46 @@ public class LibraryList extends ArrayList { super(); } - public Library getByName(String name) { - for (Library l : this) + public LibraryList(List ideLibs) { + super(ideLibs); + } + + public UserLibrary getByName(String name) { + for (UserLibrary l : this) if (l.getName().equals(name)) return l; return null; } - public void addOrReplace(Library lib) { - Library l = getByName(lib.getName()); - if (l != null) - remove(l); + public void addOrReplace(UserLibrary lib) { + remove(lib); add(lib); } - - public void addOrReplaceAll(Collection c) { - for (Library l : c) - addOrReplace(l); + + public void remove(UserLibrary lib) { + UserLibrary l = getByName(lib.getName()); + if (l != null) + super.remove(l); } public void sort() { - Collections.sort(this, Library.CASE_INSENSITIVE_ORDER); - } - - public Library search(String name, String arch) { - for (Library lib : this) { - if (!lib.getName().equals(name)) - continue; - if (!lib.supportsArchitecture(arch)) - continue; - return lib; - } - return null; - } - - public LibraryList filterByArchitecture(String reqArch) { - LibraryList res = new LibraryList(); - for (Library lib : this) - if (lib.supportsArchitecture(reqArch)) - res.add(lib); - return res; + Collections.sort(this, UserLibrary.CASE_INSENSITIVE_ORDER); } public LibraryList filterLibrariesInSubfolder(File subFolder) { LibraryList res = new LibraryList(); - for (Library lib : this) - if (FileUtils.isSubDirectory(subFolder, lib.getFolder())) + for (UserLibrary lib : this) { + if (FileUtils.isSubDirectory(subFolder, lib.getInstalledFolder())) { res.add(lib); + } + } return res; } + + public boolean hasLibrary(UserLibrary lib) { + for (UserLibrary l : this) + if (l == lib) return true; + return false; + } } + diff --git a/arduino-core/src/processing/app/packages/Library.java b/arduino-core/src/processing/app/packages/UserLibrary.java similarity index 51% rename from arduino-core/src/processing/app/packages/Library.java rename to arduino-core/src/processing/app/packages/UserLibrary.java index bf69c4edd..82d2d01ff 100644 --- a/arduino-core/src/processing/app/packages/Library.java +++ b/arduino-core/src/processing/app/packages/UserLibrary.java @@ -1,16 +1,46 @@ +/* + * This file is part of Arduino. + * + * Copyright 2014 Arduino LLC (http://www.arduino.cc/) + * + * Arduino 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 St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + */ package processing.app.packages; +import cc.arduino.contributions.libraries.ContributedLibrary; +import cc.arduino.contributions.libraries.ContributedLibraryReference; +import processing.app.helpers.FileUtils; +import processing.app.helpers.PreferencesMap; + import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; -import java.util.Comparator; +import java.util.LinkedList; import java.util.List; -import processing.app.helpers.FileUtils; -import processing.app.helpers.PreferencesMap; - -public class Library { +public class UserLibrary extends ContributedLibrary { private String name; private String version; @@ -18,44 +48,23 @@ public class Library { private String maintainer; private String sentence; private String paragraph; - private String url; + private String website; private String category; private String license; private List architectures; - private File folder; - private boolean isLegacy; - - private enum LibraryLayout { FLAT, RECURSIVE }; - private LibraryLayout layout; + private List types; + private List declaredTypes; private static final List MANDATORY_PROPERTIES = Arrays - .asList(new String[] { "name", "version", "author", "maintainer", - "sentence", "paragraph", "url" }); + .asList(new String[]{"name", "version", "author", "maintainer", + "sentence", "paragraph", "url"}); - private static final List CATEGORIES = Arrays.asList(new String[] { - "Display", "Communication", "Signal Input/Output", "Sensors", - "Device Control", "Timing", "Data Storage", "Data Processing", "Other", - "Uncategorized" }); + private static final List CATEGORIES = Arrays.asList(new String[]{ + "Display", "Communication", "Signal Input/Output", "Sensors", + "Device Control", "Timing", "Data Storage", "Data Processing", "Other", + "Uncategorized"}); - /** - * Scans inside a folder and create a Library object out of it. Automatically - * detects legacy libraries. Automatically fills metadata from - * library.properties file if found. - * - * @param libFolder - * @return - */ - static public Library create(File libFolder) throws IOException { - // A library is considered "new" if it contains a file called - // "library.properties" - File check = new File(libFolder, "library.properties"); - if (!check.exists() || !check.isFile()) - return createLegacyLibrary(libFolder); - else - return createLibrary(libFolder); - } - - private static Library createLibrary(File libFolder) throws IOException { + public static UserLibrary create(File libFolder) throws IOException { // Parse metadata File propertiesFile = new File(libFolder, "library.properties"); PreferencesMap properties = new PreferencesMap(); @@ -66,16 +75,16 @@ public class Library { // Compatibility with 1.5 rev.1 libraries: // "email" field changed to "maintainer" - if (!properties.containsKey("maintainer") && - properties.containsKey("email")) + if (!properties.containsKey("maintainer") && properties.containsKey("email")) { properties.put("maintainer", properties.get("email")); + } // Compatibility with 1.5 rev.1 libraries: // "arch" folder no longer supported File archFolder = new File(libFolder, "arch"); if (archFolder.isDirectory()) throw new IOException("'arch' folder is no longer supported! See " - + "http://goo.gl/gfFJzU for more information"); + + "http://goo.gl/gfFJzU for more information"); // Check mandatory properties for (String p : MANDATORY_PROPERTIES) @@ -93,7 +102,7 @@ public class Library { File utilFolder = new File(libFolder, "utility"); if (utilFolder.exists() && utilFolder.isDirectory()) { throw new IOException( - "Library can't use both 'src' and 'utility' folders."); + "Library can't use both 'src' and 'utility' folders."); } } else { // Layout with source code on library's root and "utility" folders @@ -104,8 +113,7 @@ public class Library { for (File file : libFolder.listFiles()) { if (file.isDirectory()) { if (FileUtils.isSCCSOrHiddenFile(file)) { - System.out.println("WARNING: Spurious " + file.getName() + - " folder in '" + properties.get("name") + "' library"); + System.out.println("WARNING: Spurious " + file.getName() + " folder in '" + properties.get("name") + "' library"); continue; } } @@ -123,110 +131,88 @@ public class Library { if (category == null) category = "Uncategorized"; if (!CATEGORIES.contains(category)) { - category = "Uncategorized"; System.out.println("WARNING: Category '" + category + "' in library " + - properties.get("name") + " is not valid. Setting to 'Uncategorized'"); + properties.get("name") + " is not valid. Setting to 'Uncategorized'"); + category = "Uncategorized"; } String license = properties.get("license"); - if (license == null) + if (license == null) { license = "Unspecified"; + } - Library res = new Library(); - res.folder = libFolder; + String types = properties.get("types"); + if (types == null) { + types = "Contributed"; + } + List typesList = new LinkedList(); + for (String type : types.split(",")) { + typesList.add(type.trim()); + } + + UserLibrary res = new UserLibrary(); + res.setInstalledFolder(libFolder); + res.setInstalled(true); res.name = properties.get("name").trim(); res.version = properties.get("version").trim(); res.author = properties.get("author").trim(); res.maintainer = properties.get("maintainer").trim(); res.sentence = properties.get("sentence").trim(); res.paragraph = properties.get("paragraph").trim(); - res.url = properties.get("url").trim(); + res.website = properties.get("url").trim(); res.category = category.trim(); res.license = license.trim(); res.architectures = archs; - res.isLegacy = false; res.layout = layout; + res.declaredTypes = typesList; return res; } - private static Library createLegacyLibrary(File libFolder) { - // construct an old style library - Library res = new Library(); - res.folder = libFolder; - res.layout = LibraryLayout.FLAT; - res.name = libFolder.getName(); - res.architectures = Arrays.asList("*"); - res.isLegacy = true; - return res; - } - - /** - * Returns true if the library declares to support the specified - * architecture (through the "architectures" property field). - * - * @param reqArch - * @return - */ - public boolean supportsArchitecture(String reqArch) { - return architectures.contains(reqArch) || architectures.contains("*"); - } - - /** - * Returns true if the library declares to support at least one of the - * specified architectures. - * - * @param reqArchs - * A List of architectures to check - * @return - */ - public boolean supportsArchitecture(List reqArchs) { - if (reqArchs.contains("*")) - return true; - for (String reqArch : reqArchs) - if (supportsArchitecture(reqArch)) - return true; - return false; - } - - public static final Comparator CASE_INSENSITIVE_ORDER = new Comparator() { - @Override - public int compare(Library o1, Library o2) { - return o1.getName().compareToIgnoreCase(o2.getName()); - } - }; - + @Override public String getName() { return name; } - public File getFolder() { - return folder; - } - + @Override public List getArchitectures() { return architectures; } + @Override public String getAuthor() { return author; } + @Override public String getParagraph() { return paragraph; } + @Override public String getSentence() { return sentence; } - public String getUrl() { - return url; + @Override + public String getWebsite() { + return website; } + @Override public String getCategory() { return category; } + @Override + public List getTypes() { + return types; + } + + public void setTypes(List types) { + this.types = types; + } + + @Override public String getLicense() { return license; } @@ -235,44 +221,82 @@ public class Library { return CATEGORIES; } + @Override + public void setCategory(String category) { + this.category = category; + } + + @Override public String getVersion() { return version; } + @Override public String getMaintainer() { return maintainer; } + @Override + public String getChecksum() { + return null; + } + + @Override + public long getSize() { + return 0; + } + + @Override + public String getUrl() { + return null; + } + + @Override + public String getArchiveFileName() { + return null; + } + + @Override + public List getRequires() { + return null; + } + + public List getDeclaredTypes() { + return declaredTypes; + } + + protected enum LibraryLayout { + FLAT, RECURSIVE + } + + protected LibraryLayout layout; + + public File getSrcFolder() { + switch (layout) { + case FLAT: + return getInstalledFolder(); + case RECURSIVE: + return new File(getInstalledFolder(), "src"); + default: + return null; // Keep compiler happy :-( + } + } + public boolean useRecursion() { return (layout == LibraryLayout.RECURSIVE); } - public File getSrcFolder() { - switch (layout) { - case FLAT: - return folder; - case RECURSIVE: - return new File(folder, "src"); - default: - return null; // Keep compiler happy :-( - } - } - - public boolean isLegacy() { - return isLegacy; - } - @Override public String toString() { - String res = "Library:"; - res += " (name=" + name + ")"; - res += " (version=" + version + ")"; - res += " (author=" + author + ")"; - res += " (maintainer=" + maintainer + ")"; - res += " (sentence=" + sentence + ")"; - res += " (paragraph=" + paragraph + ")"; - res += " (url=" + url + ")"; - res += " (architectures=" + architectures + ")"; + String res = "Library: " + name + "\n"; + res += " (version=" + version + ")\n"; + res += " (author=" + author + ")\n"; + res += " (maintainer=" + maintainer + ")\n"; + res += " (sentence=" + sentence + ")\n"; + res += " (paragraph=" + paragraph + ")\n"; + res += " (url=" + website + ")\n"; + res += " (architectures=" + architectures + ")\n"; return res; } + } diff --git a/arduino-core/src/processing/app/preproc/PdePreprocessor.java b/arduino-core/src/processing/app/preproc/PdePreprocessor.java index 576f7468b..dc30922a9 100644 --- a/arduino-core/src/processing/app/preproc/PdePreprocessor.java +++ b/arduino-core/src/processing/app/preproc/PdePreprocessor.java @@ -42,6 +42,9 @@ import java.util.regex.*; * Class that orchestrates preprocessing p5 syntax into straight Java. */ public class PdePreprocessor { + + private static final String IMPORT_REGEX = "^\\s*#include\\s*[<\"](\\S+)[\">]"; + // stores number of built user-defined function prototypes public int prototypeCount = 0; @@ -94,10 +97,9 @@ public class PdePreprocessor { } //String importRegexp = "(?:^|\\s|;)(import\\s+)(\\S+)(\\s*;)"; - String importRegexp = "^\\s*#include\\s*[<\"](\\S+)[\">]"; programImports = new ArrayList(); - String[][] pieces = PApplet.matchAll(program, importRegexp); + String[][] pieces = PApplet.matchAll(program, IMPORT_REGEX); if (pieces != null) for (int i = 0; i < pieces.length; i++) @@ -121,6 +123,19 @@ public class PdePreprocessor { return headerCount + prototypeCount; } + public static List findIncludes(String code){ + + String[][] pieces = PApplet.matchAll(code, IMPORT_REGEX); + + ArrayList programImports = new ArrayList(); + + if (pieces != null) + for (int i = 0; i < pieces.length; i++) + programImports.add(pieces[i][1]); // the package name + + return programImports; + } + static String substituteUnicode(String program) { // check for non-ascii chars (these will be/must be in unicode format) diff --git a/arduino-core/src/processing/app/tools/ExternalProcessExecutor.java b/arduino-core/src/processing/app/tools/CollectStdOutExecutor.java similarity index 85% rename from arduino-core/src/processing/app/tools/ExternalProcessExecutor.java rename to arduino-core/src/processing/app/tools/CollectStdOutExecutor.java index 98c2d0695..b2b5f3559 100644 --- a/arduino-core/src/processing/app/tools/ExternalProcessExecutor.java +++ b/arduino-core/src/processing/app/tools/CollectStdOutExecutor.java @@ -10,9 +10,9 @@ import java.io.OutputStream; /** * Handy process executor, collecting stdout into a given OutputStream */ -public class ExternalProcessExecutor extends DefaultExecutor { +public class CollectStdOutExecutor extends DefaultExecutor { - public ExternalProcessExecutor(final OutputStream os) { + public CollectStdOutExecutor(final OutputStream stdout) { this.setStreamHandler(new ExecuteStreamHandler() { @Override public void setProcessInputStream(OutputStream outputStream) throws IOException { @@ -27,7 +27,7 @@ public class ExternalProcessExecutor extends DefaultExecutor { byte[] buf = new byte[4096]; int bytes = -1; while ((bytes = inputStream.read(buf)) != -1) { - os.write(buf, 0, bytes); + stdout.write(buf, 0, bytes); } } diff --git a/arduino-core/src/processing/app/tools/CollectStdOutStdErrExecutor.java b/arduino-core/src/processing/app/tools/CollectStdOutStdErrExecutor.java new file mode 100644 index 000000000..65bc3efaa --- /dev/null +++ b/arduino-core/src/processing/app/tools/CollectStdOutStdErrExecutor.java @@ -0,0 +1,49 @@ +package processing.app.tools; + +import org.apache.commons.exec.DefaultExecutor; +import org.apache.commons.exec.ExecuteStreamHandler; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * Handy process executor, collecting stdout and stderr into given OutputStreams + */ +public class CollectStdOutStdErrExecutor extends DefaultExecutor { + + public CollectStdOutStdErrExecutor(final OutputStream stdout, final OutputStream stderr) { + this.setStreamHandler(new ExecuteStreamHandler() { + @Override + public void setProcessInputStream(OutputStream outputStream) throws IOException { + } + + @Override + public void setProcessErrorStream(InputStream inputStream) throws IOException { + byte[] buf = new byte[4096]; + int bytes = -1; + while ((bytes = inputStream.read(buf)) != -1) { + stderr.write(buf, 0, bytes); + } + } + + @Override + public void setProcessOutputStream(InputStream inputStream) throws IOException { + byte[] buf = new byte[4096]; + int bytes = -1; + while ((bytes = inputStream.read(buf)) != -1) { + stdout.write(buf, 0, bytes); + } + } + + @Override + public void start() throws IOException { + } + + @Override + public void stop() { + } + }); + + } +} diff --git a/arduino-core/src/processing/app/tools/DoubleQuotedArgumentsOnWindowsCommandLine.java b/arduino-core/src/processing/app/tools/DoubleQuotedArgumentsOnWindowsCommandLine.java new file mode 100644 index 000000000..c0e0788e1 --- /dev/null +++ b/arduino-core/src/processing/app/tools/DoubleQuotedArgumentsOnWindowsCommandLine.java @@ -0,0 +1,35 @@ +package processing.app.tools; + +import org.apache.commons.exec.CommandLine; +import processing.app.helpers.OSUtils; + +import java.io.File; + +public class DoubleQuotedArgumentsOnWindowsCommandLine extends CommandLine { + + public DoubleQuotedArgumentsOnWindowsCommandLine(String executable) { + super(executable); + } + + public DoubleQuotedArgumentsOnWindowsCommandLine(File executable) { + super(executable); + } + + public DoubleQuotedArgumentsOnWindowsCommandLine(CommandLine other) { + super(other); + } + + @Override + public CommandLine addArgument(String argument, boolean handleQuoting) { + // Brutal hack to workaround windows command line parsing. + // http://stackoverflow.com/questions/5969724/java-runtime-exec-fails-to-escape-characters-properly + // http://msdn.microsoft.com/en-us/library/a1y7w461.aspx + // http://bugs.sun.com/view_bug.do?bug_id=6468220 + // http://bugs.sun.com/view_bug.do?bug_id=6518827 + if (argument.contains("\"") && OSUtils.isWindows()) { + argument = argument.replace("\"", "\\\""); + } + + return super.addArgument(argument, handleQuoting); + } +} diff --git a/arduino-core/src/processing/app/windows/Platform.java b/arduino-core/src/processing/app/windows/Platform.java index e7274bfb0..cfc2f497d 100644 --- a/arduino-core/src/processing/app/windows/Platform.java +++ b/arduino-core/src/processing/app/windows/Platform.java @@ -22,23 +22,21 @@ package processing.app.windows; -import com.sun.jna.Library; -import com.sun.jna.Native; - import org.apache.commons.exec.CommandLine; import org.apache.commons.exec.Executor; - import processing.app.PreferencesData; import processing.app.debug.TargetPackage; import processing.app.legacy.PApplet; import processing.app.legacy.PConstants; -import processing.app.tools.ExternalProcessExecutor; +import processing.app.tools.CollectStdOutExecutor; import processing.app.windows.Registry.REGISTRY_ROOT_KEY; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.UnsupportedEncodingException; +import java.util.LinkedList; +import java.util.List; import java.util.Map; @@ -55,7 +53,7 @@ public class Platform extends processing.app.Platform { "\\arduino.exe \"%1\""; static final String DOC = "Arduino.Document"; - public void init() { + public void init() throws IOException { super.init(); checkAssociations(); @@ -244,7 +242,7 @@ public class Platform extends processing.app.Platform { // "Access is denied" in both cygwin and the "dos" prompt. //Runtime.getRuntime().exec("cmd /c " + currentDir + "\\reference\\" + // referenceFile + ".html"); - if (url.startsWith("http://")) { + 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 @@ -281,36 +279,6 @@ public class Platform extends processing.app.Platform { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . - // Code partially thanks to Richard Quirk from: - // http://quirkygba.blogspot.com/2009/11/setting-environment-variables-in-java.html - - static WinLibC clib = (WinLibC) Native.loadLibrary("msvcrt", WinLibC.class); - - public interface WinLibC extends Library { - //WinLibC INSTANCE = (WinLibC) Native.loadLibrary("msvcrt", WinLibC.class); - //libc = Native.loadLibrary("msvcrt", WinLibC.class); - public int _putenv(String name); -} - - - public void setenv(String variable, String value) { - //WinLibC clib = WinLibC.INSTANCE; - clib._putenv(variable + "=" + value); - } - - - public String getenv(String variable) { - return System.getenv(variable); - } - - - public int unsetenv(String variable) { - //WinLibC clib = WinLibC.INSTANCE; - //clib._putenv(variable + "="); - //return 0; - return clib._putenv(variable + "="); - } - @Override public String getName() { return PConstants.platformNames[PConstants.WINDOWS]; @@ -318,6 +286,7 @@ public class Platform extends processing.app.Platform { @Override public Map resolveDeviceAttachedTo(String serial, Map packages, String devicesListOutput) { + assert packages != null; if (devicesListOutput == null) { return super.resolveDeviceAttachedTo(serial, packages, devicesListOutput); } @@ -338,7 +307,7 @@ public class Platform extends processing.app.Platform { @Override public String preListAllCandidateDevices() { ByteArrayOutputStream baos = new ByteArrayOutputStream(); - Executor executor = new ExternalProcessExecutor(baos); + Executor executor = new CollectStdOutExecutor(baos); try { String listComPorts = new File(System.getProperty("user.dir"), "hardware/tools/listComPorts.exe").getCanonicalPath(); @@ -350,4 +319,24 @@ public class Platform extends processing.app.Platform { return super.preListAllCandidateDevices(); } } + + @Override + public void fixPrefsFilePermissions(File prefsFile) throws IOException { + //noop + } + + public List postInstallScripts(File folder) { + List scripts = new LinkedList(); + scripts.add(new File(folder, "post_install.bat")); + return scripts; + } + + public void symlink(File something, File somewhere) throws IOException, InterruptedException { + } + + public void link(File something, File somewhere) throws IOException, InterruptedException { + } + + public void chmod(File file, int mode) throws IOException, InterruptedException { + } } diff --git a/build/build.xml b/build/build.xml index 20566b252..20bac52d4 100644 --- a/build/build.xml +++ b/build/build.xml @@ -4,35 +4,38 @@ + + + + - + - + + - - - + - - + + @@ -54,21 +57,14 @@ - - - - - - - - - - - + + + + @@ -115,30 +111,16 @@ - + - - - - + - - - - - - - - - - - + @@ -149,15 +131,49 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -199,9 +215,9 @@ - + - + @@ -222,8 +238,9 @@ - + + @@ -250,20 +267,21 @@ - - - - - - - - + + - + + + + + + + + + + @@ -305,16 +325,19 @@ + + @@ -325,42 +348,20 @@ + + - - - - - - - + - - - - - + - + - - - - - - - - - - - - - - - + @@ -369,54 +370,68 @@ + + + + + + + + + + + + - - - + + + + - - - - + + + + - - - - - + + + + + + - - + + - + - + - + - + - + - + @@ -432,18 +447,18 @@ - + - + - - + + @@ -454,7 +469,7 @@ - + @@ -476,16 +491,16 @@ - + - + - + @@ -498,59 +513,70 @@ - - - + + + - - - - - + + + + + - - - + + + - - - - - - - - - - + + + + + + + + + + - - + + + + + - - - - + + + + - - - - + + + + - - - + + + - - ======================================================= - Arduino for Mac OS X was built. Grab the image from + + + - macosx/arduino-${version}.dmg - ======================================================= - - + + + + + + + + + + + + + + + @@ -577,6 +603,7 @@ + @@ -596,23 +623,16 @@ + + - - - - - - - - - - + @@ -621,64 +641,54 @@ - - - - - - + + + + + + - - - - - - - + - - - - - - + + + + + + - - - - - - + + + + + + + + + - - - - + + + + - - - - - - - - - + + - - + + - - + + @@ -709,8 +719,8 @@ - Unzipping into folder ${dest_folder} - + Untarring ${archive_file} into folder ${dest_folder} + @@ -718,9 +728,9 @@ - Unzipping into folder ${dest_folder} + Unzipping ${archive_file} into folder ${dest_folder} - + @@ -729,12 +739,18 @@ + + Unzipping ${archive_file} into folder ${dest_folder} + + + + - + @@ -784,23 +800,28 @@ - - + + + + + + - - - - - - + + + + + + + @@ -824,17 +845,11 @@ - - - - - - - + - + @@ -842,13 +857,11 @@ - + - - @@ -856,6 +869,7 @@ + @@ -865,11 +879,11 @@ + includes="application.ico, config.xml, config_debug.xml, arduino.l4j.ini"/> - + @@ -877,46 +891,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -929,10 +904,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -986,4 +999,63 @@ depends="linux-clean, windows-clean, macosx-clean, subprojects-clean"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${BUILD_DATE} + + diff --git a/build/build_all_dist.bash b/build/build_all_dist.bash new file mode 100755 index 000000000..0e98b827c --- /dev/null +++ b/build/build_all_dist.bash @@ -0,0 +1,20 @@ +#!/bin/bash -ex + +DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) +cd $DIR + +rm -f ../arduino-*.tar.xz +rm -f ../arduino-*.zip + +ant -Djava.net.preferIPv4Stack=true -Dplatform=linux32 $@ clean dist +mv linux/arduino-*-linux32.tar.xz ../ + +ant -Djava.net.preferIPv4Stack=true -Dplatform=linux64 $@ clean dist +mv linux/arduino-*-linux64.tar.xz ../ + +ant -Djava.net.preferIPv4Stack=true -Dplatform=windows $@ clean dist +mv windows/arduino-*-windows.zip ../ + +ant -Djava.net.preferIPv4Stack=true -Dplatform=macosx $@ clean dist +mv macosx/arduino-*-macosx.zip ../ + diff --git a/build/build_board_manager_package.sh b/build/build_board_manager_package.sh new file mode 100755 index 000000000..3d6ba517f --- /dev/null +++ b/build/build_board_manager_package.sh @@ -0,0 +1,135 @@ +#!/bin/bash + +ver=`git describe --tags` +outdir=esp8266-$ver +srcdir=../hardware/esp8266com/esp8266/ +mkdir -p $outdir +cp -R $srcdir/* $outdir/ +cat $srcdir/platform.txt | \ +gsed 's/runtime.tools.xtensa-lx106-elf-gcc.path={runtime.platform.path}\/tools\/xtensa-lx106-elf//g' | \ +gsed 's/runtime.tools.esptool.path={runtime.platform.path}\/tools//g' | \ +gsed 's/tools.esptool.path={runtime.platform.path}\/tools/tools.esptool.path=\{runtime.tools.esptool.path\}/g' \ + > $outdir/platform.txt + +zip -r $outdir.zip $outdir +sha=`shasum -a 256 $outdir.zip | cut -f 1 -d ' '` +size=`/bin/ls -l $outdir.zip | awk '{print $5}'` +echo Size: $size +echo SHA-256: $sha + +scp $outdir.zip dl:apps/download_files/download/ + + +cat << EOF > package_esp8266com_index.json +{ + "packages": [ { + "name":"esp8266", + "maintainer":"ESP8266 Community", + "websiteURL":"https://github.com/esp8266/Arduino", + "email":"ivan@esp8266.com", + "help":{ + "online":"http://esp8266.com" + }, + + "platforms": [ { + "name":"esp8266", + "architecture":"esp8266", + "version":"$ver", + "category":"ESP8266", + "url":"http://arduino.esp8266.com/$outdir.zip", + "archiveFileName":"$outdir.zip", + "checksum":"SHA-256:$sha", + "size":"$size", + "help":{ + "online":"http://esp8266.com" + }, + "boards":[ { + "name":"Generic ESP8266 Module" + } + ], + "toolsDependencies":[ { + "packager":"esp8266", + "name":"esptool", + "version":"0.4.4" + }, + { + "packager":"esp8266", + "name":"xtensa-lx106-elf-gcc", + "version":"1.20.0-26-gb404fb9" + } ] + } ], + + "tools": [ { + "name":"esptool", + "version":"0.4.4", + "systems": [ + { + "host":"i686-mingw32", + "url":"https://github.com/igrr/esptool-ck/releases/download/0.4.4/esptool-0.4.4-win32.zip", + "archiveFileName":"esptool-0.4.4-win32.zip", + "checksum":"SHA-256:bc52165c847b194d8f079add982eae1c4b4466784bff8c8494241de602a003b3", + "size":"17262" + }, + { + "host":"x86_64-apple-darwin", + "url":"https://github.com/igrr/esptool-ck/releases/download/0.4.4/esptool-0.4.4-osx.tar.gz", + "archiveFileName":"esptool-0.4.4-osx.tar.gz", + "checksum":"SHA-256:bb2a58c3583f9dcb0d3e7611531a0f3a29c21a4a1c442987bb29d07408824dfe", + "size":"12145" + }, + { + "host":"x86_64-pc-linux-gnu", + "url":"https://github.com/igrr/esptool-ck/releases/download/0.4.4/esptool-0.4.4-linux64.tar.gz", + "archiveFileName":"esptool-0.4.4-linux64.tar.gz", + "checksum":"SHA-256:beedf89db0bdce0bf6034232d86edebcfed0966ff1501545aca9cfbba1f92593", + "size":"12513" + }, + { + "host":"i686-pc-linux-gnu", + "url":"https://github.com/igrr/esptool-ck/releases/download/0.4.4/esptool-0.4.4-linux32.tar.gz", + "archiveFileName":"esptool-0.4.4-linux32.tar.gz", + "checksum":"SHA-256:4aa81b97a470641771cf371e5d470ac92d3b177adbe8263c4aae66e607b67755", + "size":"12044" + } + ] + }, + { + "name":"xtensa-lx106-elf-gcc", + "version":"1.20.0-26-gb404fb9", + "systems": [ + { + "host":"i686-mingw32", + "url":"http://arduino.esp8266.com/win32-xtensa-lx106-elf-gb404fb9.tar.gz", + "archiveFileName":"win32-xtensa-lx106-elf-gb404fb9.tar.gz", + "checksum":"SHA-256:1561ec85cc58cab35cc48bfdb0d0087809f89c043112a2c36b54251a13bf781f", + "size":"153807368" + }, + { + "host":"x86_64-apple-darwin", + "url":"http://arduino.esp8266.com/osx-xtensa-lx106-elf-gb404fb9.tar.gz", + "archiveFileName":"osx-xtensa-lx106-elf-gb404fb9.tar.gz", + "checksum":"SHA-256:540be2ca32637584463a4a4d04717f6c79c7355e336b8c3578b0947218cf92b9", + "size":"35189446" + }, + { + "host":"x86_64-pc-linux-gnu", + "url":"http://arduino.esp8266.com/linux64-xtensa-lx106-elf-gb404fb9.tar.gz", + "archiveFileName":"linux64-xtensa-lx106-elf-gb404fb9.tar.gz", + "checksum":"SHA-256:46f057fbd8b320889a26167daf325038912096d09940b2a95489db92431473b7", + "size":"30262903" + }, + { + "host":"i686-pc-linux-gnu", + "url":"http://arduino.esp8266.com/linux32-xtensa-lx106-elf.tar.gz", + "archiveFileName":"linux32-xtensa-lx106-elf.tar.gz", + "checksum":"SHA-256:b24817819f0078fb05895a640e806e0aca9aa96b47b80d2390ac8e2d9ddc955a", + "size":"32734156" + } + ] + } ] + } ] +} +EOF + +scp package_esp8266com_index.json dl:apps/download_files/download + diff --git a/build/build_pull_request.bash b/build/build_pull_request.bash index 62398d77b..0553a4bcd 100755 --- a/build/build_pull_request.bash +++ b/build/build_pull_request.bash @@ -1,11 +1,14 @@ #!/bin/bash -ex +DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) +cd $DIR + if [ "x${ghprbPullId}" == "x" ] then exit 1 fi -ant -Djava.net.preferIPv4Stack=true -Dplatform=linux64 -Dlinux64=1 clean build test +ant -Djava.net.preferIPv4Stack=true -Dplatform=linux64 -Dlinux64=1 clean build ERRORS=`grep ' arduino.desktop +rm arduino.desktop-bak + +cp arduino.desktop ~/.local/share/applications/arduino.desktop +cp arduino.desktop ~/Desktop/arduino.desktop + +echo "Instaled Arduino IDE icons on menu and desktop !" + diff --git a/build/linux/dist/linux64-xtensa-lx106-elf-gb404fb9.tgz.sha b/build/linux/dist/linux64-xtensa-lx106-elf-gb404fb9.tgz.sha new file mode 100644 index 000000000..63a2d4e45 --- /dev/null +++ b/build/linux/dist/linux64-xtensa-lx106-elf-gb404fb9.tgz.sha @@ -0,0 +1 @@ +183d85c10ca3aabf1f57e03780fadfad589dc0bc diff --git a/build/linux/dist/linux64-xtensa-lx106-elf.tgz.sha b/build/linux/dist/linux64-xtensa-lx106-elf.tgz.sha deleted file mode 100644 index 19195a689..000000000 --- a/build/linux/dist/linux64-xtensa-lx106-elf.tgz.sha +++ /dev/null @@ -1 +0,0 @@ -43ca9c53d70655456a28c297526204447f65d9cb diff --git a/build/linux/dist/tools/adk2install b/build/linux/dist/tools/adk2install deleted file mode 100755 index 8ec59a207..000000000 --- a/build/linux/dist/tools/adk2install +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/sh - -# simple wrapper around the adk2tool and bossac to properly erase and reset the -# adk2 board - -echo $1 /dev/$2 erase -$1 /dev/$2 erase - -echo $3 --port=$2 -w -e -v -b $4 -$3 --port=$2 -w -e -v -b $4 - -echo $1 /dev/$2 reset -$1 /dev/$2 reset - diff --git a/build/linux/dist/tools/adk2tool b/build/linux/dist/tools/adk2tool deleted file mode 100755 index d951baf17..000000000 Binary files a/build/linux/dist/tools/adk2tool and /dev/null differ diff --git a/build/linux/dist/tools/bossac32 b/build/linux/dist/tools/bossac32 deleted file mode 100755 index 573e7d9e7..000000000 Binary files a/build/linux/dist/tools/bossac32 and /dev/null differ diff --git a/build/linux/dist/tools/bossac64 b/build/linux/dist/tools/bossac64 deleted file mode 100755 index c4c799438..000000000 Binary files a/build/linux/dist/tools/bossac64 and /dev/null differ diff --git a/build/linux/esptool-0.4.3-linux64.zip.sha b/build/linux/esptool-0.4.3-linux64.zip.sha deleted file mode 100644 index cafdd1a92..000000000 --- a/build/linux/esptool-0.4.3-linux64.zip.sha +++ /dev/null @@ -1 +0,0 @@ -f183d52557a50dd362fcb4d45ffd6612b328e465 diff --git a/build/linux/esptool-0.4.4-linux64.tar.gz.sha b/build/linux/esptool-0.4.4-linux64.tar.gz.sha new file mode 100644 index 000000000..18f5fabdd --- /dev/null +++ b/build/linux/esptool-0.4.4-linux64.tar.gz.sha @@ -0,0 +1 @@ +65e4b3c4a26e7960536f8f2a19c5d65a13fe8025 diff --git a/build/macosx/appbundler-1.0ea-arduino2.jar.zip.sha b/build/macosx/appbundler-1.0ea-arduino2.jar.zip.sha deleted file mode 100644 index bcf3f61e6..000000000 --- a/build/macosx/appbundler-1.0ea-arduino2.jar.zip.sha +++ /dev/null @@ -1 +0,0 @@ -929bc65f3ba6ecb868254a6328f8502ad86fe4e5 diff --git a/build/macosx/appbundler-1.0ea-upstream1.jar.zip.sha b/build/macosx/appbundler-1.0ea-upstream1.jar.zip.sha new file mode 100644 index 000000000..b8179c64c --- /dev/null +++ b/build/macosx/appbundler-1.0ea-upstream1.jar.zip.sha @@ -0,0 +1 @@ +5bb6377a65edf7af7b5b3820711bab0e377bdee1 diff --git a/build/macosx/avr-gcc-4.8.1-arduino5-i386-apple-darwin11.tar.bz2.sha b/build/macosx/avr-gcc-4.8.1-arduino5-i386-apple-darwin11.tar.bz2.sha new file mode 100644 index 000000000..a0ac6d486 --- /dev/null +++ b/build/macosx/avr-gcc-4.8.1-arduino5-i386-apple-darwin11.tar.bz2.sha @@ -0,0 +1 @@ +1ea737a217e0dde0a338fff070cc3010669ab6f1 diff --git a/build/macosx/avr-toolchain-mac32-3.4.5.zip.sha b/build/macosx/avr-toolchain-mac32-3.4.5.zip.sha deleted file mode 100644 index ff372c9ef..000000000 --- a/build/macosx/avr-toolchain-mac32-3.4.5.zip.sha +++ /dev/null @@ -1 +0,0 @@ -7883269bd9ba654ed6ca943d983c02c8691b858b diff --git a/build/macosx/avrdude-6.0.1-arduino5-i386-apple-darwin11.tar.bz2.sha b/build/macosx/avrdude-6.0.1-arduino5-i386-apple-darwin11.tar.bz2.sha new file mode 100644 index 000000000..359455e69 --- /dev/null +++ b/build/macosx/avrdude-6.0.1-arduino5-i386-apple-darwin11.tar.bz2.sha @@ -0,0 +1 @@ +1eb447a6c11f374d71e91bf4c381380216f9a476 diff --git a/build/macosx/dist/bossac b/build/macosx/dist/bossac deleted file mode 100755 index 49a20b38a..000000000 Binary files a/build/macosx/dist/bossac and /dev/null differ diff --git a/build/macosx/dist/osx-xtensa-lx106-elf-gb404fb9.tgz.sha b/build/macosx/dist/osx-xtensa-lx106-elf-gb404fb9.tgz.sha new file mode 100644 index 000000000..57ca5c3df --- /dev/null +++ b/build/macosx/dist/osx-xtensa-lx106-elf-gb404fb9.tgz.sha @@ -0,0 +1 @@ +9c1c27e8d8027292dca18c7a6b5fab69d17ae540 diff --git a/build/macosx/dist/osx-xtensa-lx106-elf.tgz b/build/macosx/dist/osx-xtensa-lx106-elf.tgz deleted file mode 100644 index d3130247f..000000000 Binary files a/build/macosx/dist/osx-xtensa-lx106-elf.tgz and /dev/null differ diff --git a/build/macosx/dist/osx-xtensa-lx106-elf.tgz.sha b/build/macosx/dist/osx-xtensa-lx106-elf.tgz.sha deleted file mode 100644 index 8bf182948..000000000 --- a/build/macosx/dist/osx-xtensa-lx106-elf.tgz.sha +++ /dev/null @@ -1 +0,0 @@ -123cd06d38cfe9f09bfad89cf209a2486221849f diff --git a/build/macosx/esptool-0.4.3-osx.zip.sha b/build/macosx/esptool-0.4.3-osx.zip.sha deleted file mode 100644 index e53e8f92d..000000000 --- a/build/macosx/esptool-0.4.3-osx.zip.sha +++ /dev/null @@ -1 +0,0 @@ -544070e40abd3a81cad554020be86157674f9794 diff --git a/build/macosx/esptool-0.4.4-osx.tar.gz.sha b/build/macosx/esptool-0.4.4-osx.tar.gz.sha new file mode 100644 index 000000000..0cf3a3d4a --- /dev/null +++ b/build/macosx/esptool-0.4.4-osx.tar.gz.sha @@ -0,0 +1 @@ +26c53e32887b0c41dab861df93a60d1688e7762b diff --git a/build/macosx/template.app/Contents/Info.plist b/build/macosx/template.app/Contents/Info.plist index 55f47f49a..6d49f00a5 100755 --- a/build/macosx/template.app/Contents/Info.plist +++ b/build/macosx/template.app/Contents/Info.plist @@ -81,12 +81,15 @@ VMOptions -Xms128M - -Xmx1024M + -Xmx512M MainClass processing.app.Base + SplashFile + $APP_PACKAGE/Contents/Resources/Java/lib/splash.png + JVMVersion 1.6* @@ -94,7 +97,7 @@ - $JAVAROOT/pde.jar:$JAVAROOT/arduino-core.jar:$JAVAROOT/antlr.jar:$JAVAROOT/apple.jar:$JAVAROOT/ecj.jar:$JAVAROOT/registry.jar:$JAVAROOT/quaqua.jar:$JAVAROOT/jssc-2.8.0.jar:$JAVAROOT/commons-codec-1.7.jar:$JAVAROOT/commons-exec-1.1.jar:$JAVAROOT/commons-httpclient-3.1.jar:$JAVAROOT/commons-logging-1.0.4.jar:$JAVAROOT/jmdns-3.4.1.jar:$JAVAROOT/jsch-0.1.50.jar:$JAVAROOT/jna.jar + $JAVAROOT/antlr.jar:$JAVAROOT/apple.jar:$JAVAROOT/arduino-core.jar:$JAVAROOT/bcpg-jdk15on-152.jar:$JAVAROOT/bcprov-jdk15on-152.jar:$JAVAROOT/commons-codec-1.7.jar:$JAVAROOT/commons-compress-1.8.jar:$JAVAROOT/commons-exec-1.1.jar:$JAVAROOT/commons-httpclient-3.1.jar:$JAVAROOT/commons-lang3-3.3.2.jar:$JAVAROOT/commons-logging-1.0.4.jar:$JAVAROOT/ecj.jar:$JAVAROOT/guava-18.0.jar:$JAVAROOT/jackson-annotations-2.2.3.jar:$JAVAROOT/jackson-core-2.2.3.jar:$JAVAROOT/jackson-databind-2.2.3.jar:$JAVAROOT/jackson-module-mrbean-2.2.3.jar:$JAVAROOT/java-semver-0.8.0.jar:$JAVAROOT/jmdns-3.4.1.jar:$JAVAROOT/jna.jar:$JAVAROOT/jsch-0.1.50.jar:$JAVAROOT/jssc-2.8.0.jar:$JAVAROOT/pde.jar:$JAVAROOT/quaqua.jar:$JAVAROOT/rsyntaxtextarea-2.5.6.1+arduino.jar JVMArchs diff --git a/build/macosx/template.app/Contents/Resources/Java/libquaqua.jnilib b/build/macosx/template.app/Contents/Resources/Java/libquaqua.jnilib index eb9b05722..9f4ecedf8 100755 Binary files a/build/macosx/template.app/Contents/Resources/Java/libquaqua.jnilib and b/build/macosx/template.app/Contents/Resources/Java/libquaqua.jnilib differ diff --git a/build/macosx/template.app/Contents/Resources/Java/libquaqua64.dylib b/build/macosx/template.app/Contents/Resources/Java/libquaqua64.dylib new file mode 100755 index 000000000..4bd3c391c Binary files /dev/null and b/build/macosx/template.app/Contents/Resources/Java/libquaqua64.dylib differ diff --git a/build/macosx/template.app/Contents/Resources/Java/libquaqua64.jnilib b/build/macosx/template.app/Contents/Resources/Java/libquaqua64.jnilib index 7e3a3cf38..4bd3c391c 100755 Binary files a/build/macosx/template.app/Contents/Resources/Java/libquaqua64.jnilib and b/build/macosx/template.app/Contents/Resources/Java/libquaqua64.jnilib differ diff --git a/build/macosx/template.app/Contents/Resources/Java/quaqua.LICENSE.BSD.LGPL-2.1.txt b/build/macosx/template.app/Contents/Resources/Java/quaqua.LICENSE.BSD.LGPL-2.1.txt new file mode 100644 index 000000000..e69de29bb diff --git a/build/macosx/template.app/Contents/Resources/Java/quaqua.jar b/build/macosx/template.app/Contents/Resources/Java/quaqua.jar old mode 100755 new mode 100644 index 510b59d4e..319aa0711 Binary files a/build/macosx/template.app/Contents/Resources/Java/quaqua.jar and b/build/macosx/template.app/Contents/Resources/Java/quaqua.jar differ diff --git a/build/shared/Edison_help_files-1.6.2.zip.sha b/build/shared/Edison_help_files-1.6.2.zip.sha new file mode 100644 index 000000000..3eae008bf --- /dev/null +++ b/build/shared/Edison_help_files-1.6.2.zip.sha @@ -0,0 +1 @@ +07a93ab86dadbb33c0182fc2e3034ed3a24cbec6 diff --git a/build/shared/Galileo_help_files-1.6.2.zip.sha b/build/shared/Galileo_help_files-1.6.2.zip.sha new file mode 100644 index 000000000..380f28cd2 --- /dev/null +++ b/build/shared/Galileo_help_files-1.6.2.zip.sha @@ -0,0 +1 @@ +494881c26e4dc58ab67409d72c3d63e3c52ac184 diff --git a/build/shared/examples/01.Basics/AnalogReadSerial/AnalogReadSerial.txt b/build/shared/examples/01.Basics/AnalogReadSerial/AnalogReadSerial.txt new file mode 100644 index 000000000..95a731d56 --- /dev/null +++ b/build/shared/examples/01.Basics/AnalogReadSerial/AnalogReadSerial.txt @@ -0,0 +1 @@ +Read a potentiometer, print its state out to the Arduino Serial Monitor. \ No newline at end of file diff --git a/build/shared/examples/01.Basics/AnalogReadSerial/layout.png b/build/shared/examples/01.Basics/AnalogReadSerial/layout.png new file mode 100644 index 000000000..89df38dc0 Binary files /dev/null and b/build/shared/examples/01.Basics/AnalogReadSerial/layout.png differ diff --git a/build/shared/examples/01.Basics/AnalogReadSerial/schematic.png b/build/shared/examples/01.Basics/AnalogReadSerial/schematic.png new file mode 100644 index 000000000..2529acd32 Binary files /dev/null and b/build/shared/examples/01.Basics/AnalogReadSerial/schematic.png differ diff --git a/build/shared/examples/01.Basics/BareMinimum/BareMinimum.txt b/build/shared/examples/01.Basics/BareMinimum/BareMinimum.txt new file mode 100644 index 000000000..522b5cd5e --- /dev/null +++ b/build/shared/examples/01.Basics/BareMinimum/BareMinimum.txt @@ -0,0 +1 @@ +The bare minimum of code needed to start an Arduino sketch. \ No newline at end of file diff --git a/build/shared/examples/01.Basics/Blink/Blink.txt b/build/shared/examples/01.Basics/Blink/Blink.txt new file mode 100644 index 000000000..06263345d --- /dev/null +++ b/build/shared/examples/01.Basics/Blink/Blink.txt @@ -0,0 +1 @@ +Turn an LED on and off. \ No newline at end of file diff --git a/build/shared/examples/01.Basics/DigitalReadSerial/DigitalReadSerial.txt b/build/shared/examples/01.Basics/DigitalReadSerial/DigitalReadSerial.txt new file mode 100644 index 000000000..a330ffe01 --- /dev/null +++ b/build/shared/examples/01.Basics/DigitalReadSerial/DigitalReadSerial.txt @@ -0,0 +1 @@ +Read a switch, print the state out to the Arduino Serial Monitor. \ No newline at end of file diff --git a/build/shared/examples/01.Basics/DigitalReadSerial/layout.png b/build/shared/examples/01.Basics/DigitalReadSerial/layout.png new file mode 100644 index 000000000..1a312f2f0 Binary files /dev/null and b/build/shared/examples/01.Basics/DigitalReadSerial/layout.png differ diff --git a/build/shared/examples/01.Basics/DigitalReadSerial/schematic.png b/build/shared/examples/01.Basics/DigitalReadSerial/schematic.png new file mode 100644 index 000000000..3d05fe903 Binary files /dev/null and b/build/shared/examples/01.Basics/DigitalReadSerial/schematic.png differ diff --git a/build/shared/examples/01.Basics/Fade/Fade.txt b/build/shared/examples/01.Basics/Fade/Fade.txt new file mode 100644 index 000000000..32d4d2890 --- /dev/null +++ b/build/shared/examples/01.Basics/Fade/Fade.txt @@ -0,0 +1 @@ +Demonstrates the use of analog output to fade an LED. \ No newline at end of file diff --git a/build/shared/examples/01.Basics/Fade/layout.png b/build/shared/examples/01.Basics/Fade/layout.png new file mode 100644 index 000000000..5a6db3e35 Binary files /dev/null and b/build/shared/examples/01.Basics/Fade/layout.png differ diff --git a/build/shared/examples/01.Basics/Fade/schematic.png b/build/shared/examples/01.Basics/Fade/schematic.png new file mode 100644 index 000000000..6dd229492 Binary files /dev/null and b/build/shared/examples/01.Basics/Fade/schematic.png differ diff --git a/build/shared/examples/01.Basics/ReadAnalogVoltage/ReadAnalogVoltage.txt b/build/shared/examples/01.Basics/ReadAnalogVoltage/ReadAnalogVoltage.txt new file mode 100644 index 000000000..d71a63d6a --- /dev/null +++ b/build/shared/examples/01.Basics/ReadAnalogVoltage/ReadAnalogVoltage.txt @@ -0,0 +1 @@ +Reads an analog input and prints the voltage to the serial monitor. \ No newline at end of file diff --git a/build/shared/examples/01.Basics/ReadAnalogVoltage/layout.png b/build/shared/examples/01.Basics/ReadAnalogVoltage/layout.png new file mode 100644 index 000000000..89df38dc0 Binary files /dev/null and b/build/shared/examples/01.Basics/ReadAnalogVoltage/layout.png differ diff --git a/build/shared/examples/01.Basics/ReadAnalogVoltage/schematic.png b/build/shared/examples/01.Basics/ReadAnalogVoltage/schematic.png new file mode 100644 index 000000000..2529acd32 Binary files /dev/null and b/build/shared/examples/01.Basics/ReadAnalogVoltage/schematic.png differ diff --git a/build/shared/examples/02.Digital/BlinkWithoutDelay/BlinkWithoutDelay.txt b/build/shared/examples/02.Digital/BlinkWithoutDelay/BlinkWithoutDelay.txt new file mode 100644 index 000000000..569c6b6e3 --- /dev/null +++ b/build/shared/examples/02.Digital/BlinkWithoutDelay/BlinkWithoutDelay.txt @@ -0,0 +1 @@ +Blinking an LED without using the delay() function. \ No newline at end of file diff --git a/build/shared/examples/02.Digital/BlinkWithoutDelay/layout.png b/build/shared/examples/02.Digital/BlinkWithoutDelay/layout.png new file mode 100644 index 000000000..b35c5436a Binary files /dev/null and b/build/shared/examples/02.Digital/BlinkWithoutDelay/layout.png differ diff --git a/build/shared/examples/02.Digital/BlinkWithoutDelay/schematic.png b/build/shared/examples/02.Digital/BlinkWithoutDelay/schematic.png new file mode 100644 index 000000000..ad7848d19 Binary files /dev/null and b/build/shared/examples/02.Digital/BlinkWithoutDelay/schematic.png differ diff --git a/build/shared/examples/02.Digital/Button/Button.txt b/build/shared/examples/02.Digital/Button/Button.txt new file mode 100644 index 000000000..c5b3123b5 --- /dev/null +++ b/build/shared/examples/02.Digital/Button/Button.txt @@ -0,0 +1 @@ +Use a pushbutton to control an LED. \ No newline at end of file diff --git a/build/shared/examples/02.Digital/Button/layout.png b/build/shared/examples/02.Digital/Button/layout.png new file mode 100644 index 000000000..1a312f2f0 Binary files /dev/null and b/build/shared/examples/02.Digital/Button/layout.png differ diff --git a/build/shared/examples/02.Digital/Button/schematic.png b/build/shared/examples/02.Digital/Button/schematic.png new file mode 100644 index 000000000..12964ff98 Binary files /dev/null and b/build/shared/examples/02.Digital/Button/schematic.png differ diff --git a/build/shared/examples/02.Digital/Debounce/Debounce.txt b/build/shared/examples/02.Digital/Debounce/Debounce.txt new file mode 100644 index 000000000..e6bd88044 --- /dev/null +++ b/build/shared/examples/02.Digital/Debounce/Debounce.txt @@ -0,0 +1 @@ +Read a pushbutton, filtering noise. \ No newline at end of file diff --git a/build/shared/examples/02.Digital/Debounce/button.png b/build/shared/examples/02.Digital/Debounce/button.png new file mode 100644 index 000000000..1a312f2f0 Binary files /dev/null and b/build/shared/examples/02.Digital/Debounce/button.png differ diff --git a/build/shared/examples/02.Digital/Debounce/schematic.png b/build/shared/examples/02.Digital/Debounce/schematic.png new file mode 100644 index 000000000..3d05fe903 Binary files /dev/null and b/build/shared/examples/02.Digital/Debounce/schematic.png differ diff --git a/build/shared/examples/02.Digital/DigitalInputPullup/DigitalInputPullup.txt b/build/shared/examples/02.Digital/DigitalInputPullup/DigitalInputPullup.txt new file mode 100644 index 000000000..170363b86 --- /dev/null +++ b/build/shared/examples/02.Digital/DigitalInputPullup/DigitalInputPullup.txt @@ -0,0 +1 @@ +Demonstrates the use of INPUT_PULLUP with pinMode(). \ No newline at end of file diff --git a/build/shared/examples/02.Digital/DigitalInputPullup/layout.png b/build/shared/examples/02.Digital/DigitalInputPullup/layout.png new file mode 100644 index 000000000..f057b8d95 Binary files /dev/null and b/build/shared/examples/02.Digital/DigitalInputPullup/layout.png differ diff --git a/build/shared/examples/02.Digital/DigitalInputPullup/schematic.png b/build/shared/examples/02.Digital/DigitalInputPullup/schematic.png new file mode 100644 index 000000000..22d0e2666 Binary files /dev/null and b/build/shared/examples/02.Digital/DigitalInputPullup/schematic.png differ diff --git a/build/shared/examples/02.Digital/StateChangeDetection/StateChangeDetection.txt b/build/shared/examples/02.Digital/StateChangeDetection/StateChangeDetection.txt new file mode 100644 index 000000000..7ec60fea8 --- /dev/null +++ b/build/shared/examples/02.Digital/StateChangeDetection/StateChangeDetection.txt @@ -0,0 +1 @@ +Counting the number of button pushes. \ No newline at end of file diff --git a/build/shared/examples/02.Digital/StateChangeDetection/layout.png b/build/shared/examples/02.Digital/StateChangeDetection/layout.png new file mode 100644 index 000000000..1a312f2f0 Binary files /dev/null and b/build/shared/examples/02.Digital/StateChangeDetection/layout.png differ diff --git a/build/shared/examples/02.Digital/StateChangeDetection/schematic.png b/build/shared/examples/02.Digital/StateChangeDetection/schematic.png new file mode 100644 index 000000000..3d05fe903 Binary files /dev/null and b/build/shared/examples/02.Digital/StateChangeDetection/schematic.png differ diff --git a/build/shared/examples/02.Digital/toneKeyboard/layout.png b/build/shared/examples/02.Digital/toneKeyboard/layout.png new file mode 100644 index 000000000..8be1d9f32 Binary files /dev/null and b/build/shared/examples/02.Digital/toneKeyboard/layout.png differ diff --git a/build/shared/examples/02.Digital/toneKeyboard/schematic.png b/build/shared/examples/02.Digital/toneKeyboard/schematic.png new file mode 100644 index 000000000..4aba04d49 Binary files /dev/null and b/build/shared/examples/02.Digital/toneKeyboard/schematic.png differ diff --git a/build/shared/examples/02.Digital/toneKeyboard/toneKeyboard.txt b/build/shared/examples/02.Digital/toneKeyboard/toneKeyboard.txt new file mode 100644 index 000000000..007ef7ba6 --- /dev/null +++ b/build/shared/examples/02.Digital/toneKeyboard/toneKeyboard.txt @@ -0,0 +1 @@ +A three-key musical keyboard using force sensors and a piezo speaker. \ No newline at end of file diff --git a/build/shared/examples/02.Digital/toneMelody/layout.png b/build/shared/examples/02.Digital/toneMelody/layout.png new file mode 100644 index 000000000..6e480b21c Binary files /dev/null and b/build/shared/examples/02.Digital/toneMelody/layout.png differ diff --git a/build/shared/examples/02.Digital/toneMelody/schematic.png b/build/shared/examples/02.Digital/toneMelody/schematic.png new file mode 100644 index 000000000..5baf5c6e6 Binary files /dev/null and b/build/shared/examples/02.Digital/toneMelody/schematic.png differ diff --git a/build/shared/examples/02.Digital/toneMelody/toneMelody.txt b/build/shared/examples/02.Digital/toneMelody/toneMelody.txt new file mode 100644 index 000000000..10aea41d6 --- /dev/null +++ b/build/shared/examples/02.Digital/toneMelody/toneMelody.txt @@ -0,0 +1 @@ +Play a melody with a Piezo speaker. \ No newline at end of file diff --git a/build/shared/examples/02.Digital/toneMultiple/layout.png b/build/shared/examples/02.Digital/toneMultiple/layout.png new file mode 100644 index 000000000..f64fe205d Binary files /dev/null and b/build/shared/examples/02.Digital/toneMultiple/layout.png differ diff --git a/build/shared/examples/02.Digital/toneMultiple/schematic.png b/build/shared/examples/02.Digital/toneMultiple/schematic.png new file mode 100644 index 000000000..b4fc8ab20 Binary files /dev/null and b/build/shared/examples/02.Digital/toneMultiple/schematic.png differ diff --git a/build/shared/examples/02.Digital/toneMultiple/toneMultiple.txt b/build/shared/examples/02.Digital/toneMultiple/toneMultiple.txt new file mode 100644 index 000000000..b94bb85a3 --- /dev/null +++ b/build/shared/examples/02.Digital/toneMultiple/toneMultiple.txt @@ -0,0 +1 @@ +Play tones on multiple speakers sequentially using the tone() command. \ No newline at end of file diff --git a/build/shared/examples/02.Digital/tonePitchFollower/layout.png b/build/shared/examples/02.Digital/tonePitchFollower/layout.png new file mode 100644 index 000000000..45d11b833 Binary files /dev/null and b/build/shared/examples/02.Digital/tonePitchFollower/layout.png differ diff --git a/build/shared/examples/02.Digital/tonePitchFollower/schematic.png b/build/shared/examples/02.Digital/tonePitchFollower/schematic.png new file mode 100644 index 000000000..1ba83cdc6 Binary files /dev/null and b/build/shared/examples/02.Digital/tonePitchFollower/schematic.png differ diff --git a/build/shared/examples/02.Digital/tonePitchFollower/tonePitchFollower.txt b/build/shared/examples/02.Digital/tonePitchFollower/tonePitchFollower.txt new file mode 100644 index 000000000..7899464b8 --- /dev/null +++ b/build/shared/examples/02.Digital/tonePitchFollower/tonePitchFollower.txt @@ -0,0 +1 @@ +Play a pitch on a piezo speaker depending on an analog input. \ No newline at end of file diff --git a/build/shared/examples/03.Analog/AnalogInOutSerial/AnalogInOutSerial.txt b/build/shared/examples/03.Analog/AnalogInOutSerial/AnalogInOutSerial.txt new file mode 100644 index 000000000..445119a4a --- /dev/null +++ b/build/shared/examples/03.Analog/AnalogInOutSerial/AnalogInOutSerial.txt @@ -0,0 +1 @@ +Read an analog input pin, map the result, and then use that data to dim or brighten an LED. \ No newline at end of file diff --git a/build/shared/examples/03.Analog/AnalogInOutSerial/layout.png b/build/shared/examples/03.Analog/AnalogInOutSerial/layout.png new file mode 100644 index 000000000..6aa3d2044 Binary files /dev/null and b/build/shared/examples/03.Analog/AnalogInOutSerial/layout.png differ diff --git a/build/shared/examples/03.Analog/AnalogInOutSerial/schematic.png b/build/shared/examples/03.Analog/AnalogInOutSerial/schematic.png new file mode 100644 index 000000000..e93207079 Binary files /dev/null and b/build/shared/examples/03.Analog/AnalogInOutSerial/schematic.png differ diff --git a/build/shared/examples/03.Analog/AnalogInput/AnalogInput.txt b/build/shared/examples/03.Analog/AnalogInput/AnalogInput.txt new file mode 100644 index 000000000..3f681a52e --- /dev/null +++ b/build/shared/examples/03.Analog/AnalogInput/AnalogInput.txt @@ -0,0 +1 @@ +Use a potentiometer to control the blinking of an LED. \ No newline at end of file diff --git a/build/shared/examples/03.Analog/AnalogInput/layout.png b/build/shared/examples/03.Analog/AnalogInput/layout.png new file mode 100644 index 000000000..8486b2afc Binary files /dev/null and b/build/shared/examples/03.Analog/AnalogInput/layout.png differ diff --git a/build/shared/examples/03.Analog/AnalogInput/schematic.png b/build/shared/examples/03.Analog/AnalogInput/schematic.png new file mode 100644 index 000000000..2529acd32 Binary files /dev/null and b/build/shared/examples/03.Analog/AnalogInput/schematic.png differ diff --git a/build/shared/examples/03.Analog/AnalogWriteMega/AnalogWriteMega.txt b/build/shared/examples/03.Analog/AnalogWriteMega/AnalogWriteMega.txt new file mode 100644 index 000000000..9fc0e2af4 --- /dev/null +++ b/build/shared/examples/03.Analog/AnalogWriteMega/AnalogWriteMega.txt @@ -0,0 +1 @@ +Fade 12 LEDs on and off, one by one, using an Arduino Mega board. \ No newline at end of file diff --git a/build/shared/examples/03.Analog/AnalogWriteMega/layout.png b/build/shared/examples/03.Analog/AnalogWriteMega/layout.png new file mode 100644 index 000000000..f1a92a477 Binary files /dev/null and b/build/shared/examples/03.Analog/AnalogWriteMega/layout.png differ diff --git a/build/shared/examples/03.Analog/AnalogWriteMega/schematic.png b/build/shared/examples/03.Analog/AnalogWriteMega/schematic.png new file mode 100644 index 000000000..2f0fa28f5 Binary files /dev/null and b/build/shared/examples/03.Analog/AnalogWriteMega/schematic.png differ diff --git a/build/shared/examples/03.Analog/Calibration/Calibration.txt b/build/shared/examples/03.Analog/Calibration/Calibration.txt new file mode 100644 index 000000000..dcdeb7100 --- /dev/null +++ b/build/shared/examples/03.Analog/Calibration/Calibration.txt @@ -0,0 +1 @@ +Define a maximum and minimum for expected analog sensor values. \ No newline at end of file diff --git a/build/shared/examples/03.Analog/Calibration/layout.png b/build/shared/examples/03.Analog/Calibration/layout.png new file mode 100644 index 000000000..2e6cb4276 Binary files /dev/null and b/build/shared/examples/03.Analog/Calibration/layout.png differ diff --git a/build/shared/examples/03.Analog/Calibration/schematic.png b/build/shared/examples/03.Analog/Calibration/schematic.png new file mode 100644 index 000000000..915668438 Binary files /dev/null and b/build/shared/examples/03.Analog/Calibration/schematic.png differ diff --git a/build/shared/examples/03.Analog/Fading/Fading.txt b/build/shared/examples/03.Analog/Fading/Fading.txt new file mode 100644 index 000000000..4f7998584 --- /dev/null +++ b/build/shared/examples/03.Analog/Fading/Fading.txt @@ -0,0 +1 @@ +Use an analog output (PWM pin) to fade an LED. \ No newline at end of file diff --git a/build/shared/examples/03.Analog/Fading/layout.png b/build/shared/examples/03.Analog/Fading/layout.png new file mode 100644 index 000000000..e1330feaf Binary files /dev/null and b/build/shared/examples/03.Analog/Fading/layout.png differ diff --git a/build/shared/examples/03.Analog/Fading/schematic.png b/build/shared/examples/03.Analog/Fading/schematic.png new file mode 100644 index 000000000..a89de3733 Binary files /dev/null and b/build/shared/examples/03.Analog/Fading/schematic.png differ diff --git a/build/shared/examples/03.Analog/Smoothing/Smoothing.txt b/build/shared/examples/03.Analog/Smoothing/Smoothing.txt new file mode 100644 index 000000000..64c82a05f --- /dev/null +++ b/build/shared/examples/03.Analog/Smoothing/Smoothing.txt @@ -0,0 +1 @@ +Smooth multiple readings of an analog input. \ No newline at end of file diff --git a/build/shared/examples/03.Analog/Smoothing/layout.png b/build/shared/examples/03.Analog/Smoothing/layout.png new file mode 100644 index 000000000..8486b2afc Binary files /dev/null and b/build/shared/examples/03.Analog/Smoothing/layout.png differ diff --git a/build/shared/examples/03.Analog/Smoothing/schematic.png b/build/shared/examples/03.Analog/Smoothing/schematic.png new file mode 100644 index 000000000..2529acd32 Binary files /dev/null and b/build/shared/examples/03.Analog/Smoothing/schematic.png differ diff --git a/build/shared/examples/04.Communication/ASCIITable/ASCIITable.txt b/build/shared/examples/04.Communication/ASCIITable/ASCIITable.txt new file mode 100644 index 000000000..dc492ef13 --- /dev/null +++ b/build/shared/examples/04.Communication/ASCIITable/ASCIITable.txt @@ -0,0 +1 @@ +Demonstrates Arduino's advanced serial output functions. \ No newline at end of file diff --git a/build/shared/examples/04.Communication/Dimmer/Dimmer.txt b/build/shared/examples/04.Communication/Dimmer/Dimmer.txt new file mode 100644 index 000000000..c71de2bb3 --- /dev/null +++ b/build/shared/examples/04.Communication/Dimmer/Dimmer.txt @@ -0,0 +1 @@ +Move the mouse to change the brightness of an LED. \ No newline at end of file diff --git a/build/shared/examples/04.Communication/Dimmer/layout.png b/build/shared/examples/04.Communication/Dimmer/layout.png new file mode 100644 index 000000000..e1330feaf Binary files /dev/null and b/build/shared/examples/04.Communication/Dimmer/layout.png differ diff --git a/build/shared/examples/04.Communication/Dimmer/schematic.png b/build/shared/examples/04.Communication/Dimmer/schematic.png new file mode 100644 index 000000000..6dd229492 Binary files /dev/null and b/build/shared/examples/04.Communication/Dimmer/schematic.png differ diff --git a/build/shared/examples/04.Communication/Graph/Graph.txt b/build/shared/examples/04.Communication/Graph/Graph.txt new file mode 100644 index 000000000..9ca77a31a --- /dev/null +++ b/build/shared/examples/04.Communication/Graph/Graph.txt @@ -0,0 +1 @@ +Send data to the computer and graph it in Processing. \ No newline at end of file diff --git a/build/shared/examples/04.Communication/Graph/layout.png b/build/shared/examples/04.Communication/Graph/layout.png new file mode 100644 index 000000000..8486b2afc Binary files /dev/null and b/build/shared/examples/04.Communication/Graph/layout.png differ diff --git a/build/shared/examples/04.Communication/Graph/schematic.png b/build/shared/examples/04.Communication/Graph/schematic.png new file mode 100644 index 000000000..2529acd32 Binary files /dev/null and b/build/shared/examples/04.Communication/Graph/schematic.png differ diff --git a/build/shared/examples/04.Communication/Midi/MIDI.txt b/build/shared/examples/04.Communication/Midi/MIDI.txt new file mode 100644 index 000000000..6c4bb5e66 --- /dev/null +++ b/build/shared/examples/04.Communication/Midi/MIDI.txt @@ -0,0 +1 @@ +Send MIDI note messages serially. \ No newline at end of file diff --git a/build/shared/examples/04.Communication/Midi/layout.png b/build/shared/examples/04.Communication/Midi/layout.png new file mode 100644 index 000000000..5fa9bd5f6 Binary files /dev/null and b/build/shared/examples/04.Communication/Midi/layout.png differ diff --git a/build/shared/examples/04.Communication/Midi/schematic.png b/build/shared/examples/04.Communication/Midi/schematic.png new file mode 100644 index 000000000..aebd8b28b Binary files /dev/null and b/build/shared/examples/04.Communication/Midi/schematic.png differ diff --git a/build/shared/examples/04.Communication/MultiSerialMega/MultiSerialMega.txt b/build/shared/examples/04.Communication/MultiSerialMega/MultiSerialMega.txt new file mode 100644 index 000000000..3383c9026 --- /dev/null +++ b/build/shared/examples/04.Communication/MultiSerialMega/MultiSerialMega.txt @@ -0,0 +1 @@ +Use two of the serial ports available on the Arduino Mega. \ No newline at end of file diff --git a/build/shared/examples/04.Communication/PhysicalPixel/PhysicalPixel.txt b/build/shared/examples/04.Communication/PhysicalPixel/PhysicalPixel.txt new file mode 100644 index 000000000..ad6c2991e --- /dev/null +++ b/build/shared/examples/04.Communication/PhysicalPixel/PhysicalPixel.txt @@ -0,0 +1 @@ +Turn a LED on and off by sending data to your Arduino from Processing or Max/MSP. \ No newline at end of file diff --git a/build/shared/examples/04.Communication/PhysicalPixel/layout.png b/build/shared/examples/04.Communication/PhysicalPixel/layout.png new file mode 100644 index 000000000..b35c5436a Binary files /dev/null and b/build/shared/examples/04.Communication/PhysicalPixel/layout.png differ diff --git a/build/shared/examples/04.Communication/PhysicalPixel/schematic.png b/build/shared/examples/04.Communication/PhysicalPixel/schematic.png new file mode 100644 index 000000000..ad7848d19 Binary files /dev/null and b/build/shared/examples/04.Communication/PhysicalPixel/schematic.png differ diff --git a/build/shared/examples/04.Communication/ReadASCIIString/ReadASCIIString.txt b/build/shared/examples/04.Communication/ReadASCIIString/ReadASCIIString.txt new file mode 100644 index 000000000..b2862c9b3 --- /dev/null +++ b/build/shared/examples/04.Communication/ReadASCIIString/ReadASCIIString.txt @@ -0,0 +1 @@ +Parse a comma-separated string of ints to fade an LED. \ No newline at end of file diff --git a/build/shared/examples/04.Communication/ReadASCIIString/layout.png b/build/shared/examples/04.Communication/ReadASCIIString/layout.png new file mode 100644 index 000000000..56d2b70d0 Binary files /dev/null and b/build/shared/examples/04.Communication/ReadASCIIString/layout.png differ diff --git a/build/shared/examples/04.Communication/SerialCallResponse/SerialCallResponse.txt b/build/shared/examples/04.Communication/SerialCallResponse/SerialCallResponse.txt new file mode 100644 index 000000000..4eae05f9d --- /dev/null +++ b/build/shared/examples/04.Communication/SerialCallResponse/SerialCallResponse.txt @@ -0,0 +1 @@ +Send multiple variables using a call-and-response (handshaking) method. \ No newline at end of file diff --git a/build/shared/examples/04.Communication/SerialCallResponse/layout.png b/build/shared/examples/04.Communication/SerialCallResponse/layout.png new file mode 100644 index 000000000..336b2dad9 Binary files /dev/null and b/build/shared/examples/04.Communication/SerialCallResponse/layout.png differ diff --git a/build/shared/examples/04.Communication/SerialCallResponse/schematic.png b/build/shared/examples/04.Communication/SerialCallResponse/schematic.png new file mode 100644 index 000000000..eacdf44ef Binary files /dev/null and b/build/shared/examples/04.Communication/SerialCallResponse/schematic.png differ diff --git a/build/shared/examples/04.Communication/SerialCallResponseASCII/SerialCallResponseASCII.txt b/build/shared/examples/04.Communication/SerialCallResponseASCII/SerialCallResponseASCII.txt new file mode 100644 index 000000000..e86764500 --- /dev/null +++ b/build/shared/examples/04.Communication/SerialCallResponseASCII/SerialCallResponseASCII.txt @@ -0,0 +1 @@ +Send multiple variables using a call-and-response (handshaking) method, and ASCII-encode the values before sending. \ No newline at end of file diff --git a/build/shared/examples/04.Communication/SerialCallResponseASCII/layout.png b/build/shared/examples/04.Communication/SerialCallResponseASCII/layout.png new file mode 100644 index 000000000..336b2dad9 Binary files /dev/null and b/build/shared/examples/04.Communication/SerialCallResponseASCII/layout.png differ diff --git a/build/shared/examples/04.Communication/SerialCallResponseASCII/schematic.png b/build/shared/examples/04.Communication/SerialCallResponseASCII/schematic.png new file mode 100644 index 000000000..eacdf44ef Binary files /dev/null and b/build/shared/examples/04.Communication/SerialCallResponseASCII/schematic.png differ diff --git a/build/shared/examples/04.Communication/SerialEvent/SerialEvent.txt b/build/shared/examples/04.Communication/SerialEvent/SerialEvent.txt new file mode 100644 index 000000000..c02db65b4 --- /dev/null +++ b/build/shared/examples/04.Communication/SerialEvent/SerialEvent.txt @@ -0,0 +1 @@ +Demonstrates the use of SerialEvent(). \ No newline at end of file diff --git a/build/shared/examples/04.Communication/VirtualColorMixer/VirtualColorMixer.txt b/build/shared/examples/04.Communication/VirtualColorMixer/VirtualColorMixer.txt new file mode 100644 index 000000000..e7d85c113 --- /dev/null +++ b/build/shared/examples/04.Communication/VirtualColorMixer/VirtualColorMixer.txt @@ -0,0 +1 @@ +Send multiple variables from Arduino to your computer and read them in Processing or Max/MSP. \ No newline at end of file diff --git a/build/shared/examples/04.Communication/VirtualColorMixer/layout.png b/build/shared/examples/04.Communication/VirtualColorMixer/layout.png new file mode 100644 index 000000000..cb5b7280c Binary files /dev/null and b/build/shared/examples/04.Communication/VirtualColorMixer/layout.png differ diff --git a/build/shared/examples/04.Communication/VirtualColorMixer/schematic.png b/build/shared/examples/04.Communication/VirtualColorMixer/schematic.png new file mode 100644 index 000000000..acf35b32e Binary files /dev/null and b/build/shared/examples/04.Communication/VirtualColorMixer/schematic.png differ diff --git a/build/shared/examples/05.Control/Arrays/Arrays.txt b/build/shared/examples/05.Control/Arrays/Arrays.txt new file mode 100644 index 000000000..106d99173 --- /dev/null +++ b/build/shared/examples/05.Control/Arrays/Arrays.txt @@ -0,0 +1 @@ +A variation on the For Loop example that demonstrates how to use an array. \ No newline at end of file diff --git a/build/shared/examples/05.Control/Arrays/layout.png b/build/shared/examples/05.Control/Arrays/layout.png new file mode 100644 index 000000000..c2c01516a Binary files /dev/null and b/build/shared/examples/05.Control/Arrays/layout.png differ diff --git a/build/shared/examples/05.Control/Arrays/schematic.png b/build/shared/examples/05.Control/Arrays/schematic.png new file mode 100644 index 000000000..ed9b31502 Binary files /dev/null and b/build/shared/examples/05.Control/Arrays/schematic.png differ diff --git a/build/shared/examples/05.Control/ForLoopIteration/ForLoopIteration.txt b/build/shared/examples/05.Control/ForLoopIteration/ForLoopIteration.txt new file mode 100644 index 000000000..8c6a729f9 --- /dev/null +++ b/build/shared/examples/05.Control/ForLoopIteration/ForLoopIteration.txt @@ -0,0 +1 @@ +Controlling multiple LEDs with a for loop and. \ No newline at end of file diff --git a/build/shared/examples/05.Control/ForLoopIteration/layout.png b/build/shared/examples/05.Control/ForLoopIteration/layout.png new file mode 100644 index 000000000..c2c01516a Binary files /dev/null and b/build/shared/examples/05.Control/ForLoopIteration/layout.png differ diff --git a/build/shared/examples/05.Control/ForLoopIteration/schematic.png b/build/shared/examples/05.Control/ForLoopIteration/schematic.png new file mode 100644 index 000000000..ed9b31502 Binary files /dev/null and b/build/shared/examples/05.Control/ForLoopIteration/schematic.png differ diff --git a/build/shared/examples/05.Control/IfStatementConditional/IfStatementConditional.txt b/build/shared/examples/05.Control/IfStatementConditional/IfStatementConditional.txt new file mode 100644 index 000000000..e1cdaa8f5 --- /dev/null +++ b/build/shared/examples/05.Control/IfStatementConditional/IfStatementConditional.txt @@ -0,0 +1 @@ +How to use an if statement to change output conditions based on changing input conditions. \ No newline at end of file diff --git a/build/shared/examples/05.Control/IfStatementConditional/layout.png b/build/shared/examples/05.Control/IfStatementConditional/layout.png new file mode 100644 index 000000000..6071705e4 Binary files /dev/null and b/build/shared/examples/05.Control/IfStatementConditional/layout.png differ diff --git a/build/shared/examples/05.Control/IfStatementConditional/schematic.png b/build/shared/examples/05.Control/IfStatementConditional/schematic.png new file mode 100644 index 000000000..ea56b636a Binary files /dev/null and b/build/shared/examples/05.Control/IfStatementConditional/schematic.png differ diff --git a/build/shared/examples/05.Control/WhileStatementConditional/WhileStatementConditional.txt b/build/shared/examples/05.Control/WhileStatementConditional/WhileStatementConditional.txt new file mode 100644 index 000000000..233877c59 --- /dev/null +++ b/build/shared/examples/05.Control/WhileStatementConditional/WhileStatementConditional.txt @@ -0,0 +1 @@ +How to use a while loop to calibrate a sensor while a button is being read. \ No newline at end of file diff --git a/build/shared/examples/05.Control/WhileStatementConditional/layout.png b/build/shared/examples/05.Control/WhileStatementConditional/layout.png new file mode 100644 index 000000000..8f9aab85f Binary files /dev/null and b/build/shared/examples/05.Control/WhileStatementConditional/layout.png differ diff --git a/build/shared/examples/05.Control/WhileStatementConditional/schematic.png b/build/shared/examples/05.Control/WhileStatementConditional/schematic.png new file mode 100644 index 000000000..d62dc15bc Binary files /dev/null and b/build/shared/examples/05.Control/WhileStatementConditional/schematic.png differ diff --git a/build/shared/examples/05.Control/switchCase/layout.png b/build/shared/examples/05.Control/switchCase/layout.png new file mode 100644 index 000000000..b7718079c Binary files /dev/null and b/build/shared/examples/05.Control/switchCase/layout.png differ diff --git a/build/shared/examples/05.Control/switchCase/schematic.png b/build/shared/examples/05.Control/switchCase/schematic.png new file mode 100644 index 000000000..bcd0c3dff Binary files /dev/null and b/build/shared/examples/05.Control/switchCase/schematic.png differ diff --git a/build/shared/examples/05.Control/switchCase/switchCase.txt b/build/shared/examples/05.Control/switchCase/switchCase.txt new file mode 100644 index 000000000..38568a82e --- /dev/null +++ b/build/shared/examples/05.Control/switchCase/switchCase.txt @@ -0,0 +1 @@ +How to choose between a discrete number of values. \ No newline at end of file diff --git a/build/shared/examples/05.Control/switchCase2/layout.png b/build/shared/examples/05.Control/switchCase2/layout.png new file mode 100644 index 000000000..cd9675715 Binary files /dev/null and b/build/shared/examples/05.Control/switchCase2/layout.png differ diff --git a/build/shared/examples/05.Control/switchCase2/schematic.png b/build/shared/examples/05.Control/switchCase2/schematic.png new file mode 100644 index 000000000..ed9b31502 Binary files /dev/null and b/build/shared/examples/05.Control/switchCase2/schematic.png differ diff --git a/build/shared/examples/05.Control/switchCase2/switchCase2.txt b/build/shared/examples/05.Control/switchCase2/switchCase2.txt new file mode 100644 index 000000000..fddc826bf --- /dev/null +++ b/build/shared/examples/05.Control/switchCase2/switchCase2.txt @@ -0,0 +1 @@ +A second switch-case example, showing how to take different actions based in characters received in the serial port. \ No newline at end of file diff --git a/build/shared/examples/06.Sensors/ADXL3xx/ADXL3xx.txt b/build/shared/examples/06.Sensors/ADXL3xx/ADXL3xx.txt new file mode 100644 index 000000000..a13994aba --- /dev/null +++ b/build/shared/examples/06.Sensors/ADXL3xx/ADXL3xx.txt @@ -0,0 +1 @@ +Read an ADXL3xx accelerometer. \ No newline at end of file diff --git a/build/shared/examples/06.Sensors/ADXL3xx/layout.png b/build/shared/examples/06.Sensors/ADXL3xx/layout.png new file mode 100644 index 000000000..3e35d533d Binary files /dev/null and b/build/shared/examples/06.Sensors/ADXL3xx/layout.png differ diff --git a/build/shared/examples/06.Sensors/ADXL3xx/schematic.png b/build/shared/examples/06.Sensors/ADXL3xx/schematic.png new file mode 100644 index 000000000..b3081b78c Binary files /dev/null and b/build/shared/examples/06.Sensors/ADXL3xx/schematic.png differ diff --git a/build/shared/examples/06.Sensors/Knock/Knock.txt b/build/shared/examples/06.Sensors/Knock/Knock.txt new file mode 100644 index 000000000..d93677ef4 --- /dev/null +++ b/build/shared/examples/06.Sensors/Knock/Knock.txt @@ -0,0 +1 @@ +Detect knocks with a piezo element. \ No newline at end of file diff --git a/build/shared/examples/06.Sensors/Knock/layout.png b/build/shared/examples/06.Sensors/Knock/layout.png new file mode 100644 index 000000000..d962757bc Binary files /dev/null and b/build/shared/examples/06.Sensors/Knock/layout.png differ diff --git a/build/shared/examples/06.Sensors/Knock/schematic.png b/build/shared/examples/06.Sensors/Knock/schematic.png new file mode 100644 index 000000000..6e18bf11e Binary files /dev/null and b/build/shared/examples/06.Sensors/Knock/schematic.png differ diff --git a/build/shared/examples/06.Sensors/Memsic2125/Memsic2125.txt b/build/shared/examples/06.Sensors/Memsic2125/Memsic2125.txt new file mode 100644 index 000000000..04bd5ece6 --- /dev/null +++ b/build/shared/examples/06.Sensors/Memsic2125/Memsic2125.txt @@ -0,0 +1 @@ +Two-axis acceleromoter. \ No newline at end of file diff --git a/build/shared/examples/06.Sensors/Memsic2125/layout.png b/build/shared/examples/06.Sensors/Memsic2125/layout.png new file mode 100644 index 000000000..645f792b0 Binary files /dev/null and b/build/shared/examples/06.Sensors/Memsic2125/layout.png differ diff --git a/build/shared/examples/06.Sensors/Memsic2125/schematic.png b/build/shared/examples/06.Sensors/Memsic2125/schematic.png new file mode 100644 index 000000000..df26fe929 Binary files /dev/null and b/build/shared/examples/06.Sensors/Memsic2125/schematic.png differ diff --git a/build/shared/examples/06.Sensors/Ping/Ping.txt b/build/shared/examples/06.Sensors/Ping/Ping.txt new file mode 100644 index 000000000..9746c7568 --- /dev/null +++ b/build/shared/examples/06.Sensors/Ping/Ping.txt @@ -0,0 +1 @@ +Detecting objects with an ultrasonic range finder. \ No newline at end of file diff --git a/build/shared/examples/06.Sensors/Ping/layout.png b/build/shared/examples/06.Sensors/Ping/layout.png new file mode 100644 index 000000000..0c93f0132 Binary files /dev/null and b/build/shared/examples/06.Sensors/Ping/layout.png differ diff --git a/build/shared/examples/06.Sensors/Ping/schematic.png b/build/shared/examples/06.Sensors/Ping/schematic.png new file mode 100644 index 000000000..ca4ebc405 Binary files /dev/null and b/build/shared/examples/06.Sensors/Ping/schematic.png differ diff --git a/build/shared/examples/07.Display/RowColumnScanning/RowColumnScanning.txt b/build/shared/examples/07.Display/RowColumnScanning/RowColumnScanning.txt new file mode 100644 index 000000000..d7cebdce2 --- /dev/null +++ b/build/shared/examples/07.Display/RowColumnScanning/RowColumnScanning.txt @@ -0,0 +1 @@ +How to control an 8x8 matrix of LEDs. \ No newline at end of file diff --git a/build/shared/examples/07.Display/RowColumnScanning/layout.png b/build/shared/examples/07.Display/RowColumnScanning/layout.png new file mode 100644 index 000000000..3187fbe20 Binary files /dev/null and b/build/shared/examples/07.Display/RowColumnScanning/layout.png differ diff --git a/build/shared/examples/07.Display/RowColumnScanning/schematic.png b/build/shared/examples/07.Display/RowColumnScanning/schematic.png new file mode 100644 index 000000000..238d251c7 Binary files /dev/null and b/build/shared/examples/07.Display/RowColumnScanning/schematic.png differ diff --git a/build/shared/examples/07.Display/barGraph/LEDBarGraph.txt b/build/shared/examples/07.Display/barGraph/LEDBarGraph.txt new file mode 100644 index 000000000..969634a66 --- /dev/null +++ b/build/shared/examples/07.Display/barGraph/LEDBarGraph.txt @@ -0,0 +1 @@ +How to make an LED bar graph. \ No newline at end of file diff --git a/build/shared/examples/07.Display/barGraph/layout.png b/build/shared/examples/07.Display/barGraph/layout.png new file mode 100644 index 000000000..cf676835f Binary files /dev/null and b/build/shared/examples/07.Display/barGraph/layout.png differ diff --git a/build/shared/examples/07.Display/barGraph/schematic.png b/build/shared/examples/07.Display/barGraph/schematic.png new file mode 100644 index 000000000..dfc051342 Binary files /dev/null and b/build/shared/examples/07.Display/barGraph/schematic.png differ diff --git a/build/shared/examples/08.Strings/StringAdditionOperator/StringAdditionOperator.txt b/build/shared/examples/08.Strings/StringAdditionOperator/StringAdditionOperator.txt new file mode 100644 index 000000000..c93c9f83a --- /dev/null +++ b/build/shared/examples/08.Strings/StringAdditionOperator/StringAdditionOperator.txt @@ -0,0 +1 @@ +Add strings together in a variety of ways. \ No newline at end of file diff --git a/build/shared/examples/08.Strings/StringCaseChanges/StringCaseChanges.txt b/build/shared/examples/08.Strings/StringCaseChanges/StringCaseChanges.txt new file mode 100644 index 000000000..75d11af3f --- /dev/null +++ b/build/shared/examples/08.Strings/StringCaseChanges/StringCaseChanges.txt @@ -0,0 +1 @@ +Change the case of a string. \ No newline at end of file diff --git a/build/shared/examples/08.Strings/StringCharacters/StringCharacters.txt b/build/shared/examples/08.Strings/StringCharacters/StringCharacters.txt new file mode 100644 index 000000000..d43da1f02 --- /dev/null +++ b/build/shared/examples/08.Strings/StringCharacters/StringCharacters.txt @@ -0,0 +1 @@ +Get/set the value of a specific character in a string. \ No newline at end of file diff --git a/build/shared/examples/08.Strings/StringComparisonOperators/StringComparisonOperators.txt b/build/shared/examples/08.Strings/StringComparisonOperators/StringComparisonOperators.txt new file mode 100644 index 000000000..aa622c764 --- /dev/null +++ b/build/shared/examples/08.Strings/StringComparisonOperators/StringComparisonOperators.txt @@ -0,0 +1 @@ +Compare strings alphabetically. \ No newline at end of file diff --git a/build/shared/examples/08.Strings/StringConstructors/StringConstructors.txt b/build/shared/examples/08.Strings/StringConstructors/StringConstructors.txt new file mode 100644 index 000000000..777082fb7 --- /dev/null +++ b/build/shared/examples/08.Strings/StringConstructors/StringConstructors.txt @@ -0,0 +1 @@ +How to initialize string objects. \ No newline at end of file diff --git a/build/shared/examples/08.Strings/StringIndexOf/StringIndexOf.txt b/build/shared/examples/08.Strings/StringIndexOf/StringIndexOf.txt new file mode 100644 index 000000000..cd9722953 --- /dev/null +++ b/build/shared/examples/08.Strings/StringIndexOf/StringIndexOf.txt @@ -0,0 +1 @@ +Look for the first/last instance of a character in a string. \ No newline at end of file diff --git a/build/shared/examples/08.Strings/StringLength/StringLength.txt b/build/shared/examples/08.Strings/StringLength/StringLength.txt new file mode 100644 index 000000000..862d0476e --- /dev/null +++ b/build/shared/examples/08.Strings/StringLength/StringLength.txt @@ -0,0 +1 @@ +Get and trim the length of a string. \ No newline at end of file diff --git a/build/shared/examples/08.Strings/StringLengthTrim/StringLengthTrim.txt b/build/shared/examples/08.Strings/StringLengthTrim/StringLengthTrim.txt new file mode 100644 index 000000000..862d0476e --- /dev/null +++ b/build/shared/examples/08.Strings/StringLengthTrim/StringLengthTrim.txt @@ -0,0 +1 @@ +Get and trim the length of a string. \ No newline at end of file diff --git a/build/shared/examples/08.Strings/StringReplace/StringReplace.txt b/build/shared/examples/08.Strings/StringReplace/StringReplace.txt new file mode 100644 index 000000000..f4034a756 --- /dev/null +++ b/build/shared/examples/08.Strings/StringReplace/StringReplace.txt @@ -0,0 +1 @@ +Replace individual characters in a string. \ No newline at end of file diff --git a/build/shared/examples/08.Strings/StringStartsWithEndsWith/StringStartsWithEndsWith.txt b/build/shared/examples/08.Strings/StringStartsWithEndsWith/StringStartsWithEndsWith.txt new file mode 100644 index 000000000..dac7903a9 --- /dev/null +++ b/build/shared/examples/08.Strings/StringStartsWithEndsWith/StringStartsWithEndsWith.txt @@ -0,0 +1 @@ +Check which characters/substrings a given string starts or ends with. \ No newline at end of file diff --git a/build/shared/examples/08.Strings/StringSubstring/StringSubstring.txt b/build/shared/examples/08.Strings/StringSubstring/StringSubstring.txt new file mode 100644 index 000000000..357db4d05 --- /dev/null +++ b/build/shared/examples/08.Strings/StringSubstring/StringSubstring.txt @@ -0,0 +1 @@ +Look for "phrases" within a given string. \ No newline at end of file diff --git a/build/shared/examples/09.USB/Keyboard/KeyboardLogout/KeyboardLogout.txt b/build/shared/examples/09.USB/Keyboard/KeyboardLogout/KeyboardLogout.txt new file mode 100644 index 000000000..6d1900b13 --- /dev/null +++ b/build/shared/examples/09.USB/Keyboard/KeyboardLogout/KeyboardLogout.txt @@ -0,0 +1 @@ +Logs out the current user with key commands. \ No newline at end of file diff --git a/build/shared/examples/09.USB/Keyboard/KeyboardMessage/KeyboardMessage.txt b/build/shared/examples/09.USB/Keyboard/KeyboardMessage/KeyboardMessage.txt new file mode 100644 index 000000000..86fc2be23 --- /dev/null +++ b/build/shared/examples/09.USB/Keyboard/KeyboardMessage/KeyboardMessage.txt @@ -0,0 +1 @@ +Sends a text string when a button is pressed. \ No newline at end of file diff --git a/build/shared/examples/09.USB/Keyboard/KeyboardMessage/layout.png b/build/shared/examples/09.USB/Keyboard/KeyboardMessage/layout.png new file mode 100644 index 000000000..622a9a5b0 Binary files /dev/null and b/build/shared/examples/09.USB/Keyboard/KeyboardMessage/layout.png differ diff --git a/build/shared/examples/09.USB/Keyboard/KeyboardMessage/schematic.png b/build/shared/examples/09.USB/Keyboard/KeyboardMessage/schematic.png new file mode 100644 index 000000000..ef19b85a6 Binary files /dev/null and b/build/shared/examples/09.USB/Keyboard/KeyboardMessage/schematic.png differ diff --git a/build/shared/examples/09.USB/Keyboard/KeyboardReprogram/KeyboardReprogram.txt b/build/shared/examples/09.USB/Keyboard/KeyboardReprogram/KeyboardReprogram.txt new file mode 100644 index 000000000..0ccbf5fc3 --- /dev/null +++ b/build/shared/examples/09.USB/Keyboard/KeyboardReprogram/KeyboardReprogram.txt @@ -0,0 +1 @@ +Opens a new window in the Arduino IDE and reprograms the Leonardo with a simple blink program. \ No newline at end of file diff --git a/build/shared/examples/09.USB/Keyboard/KeyboardSerial/KeyboardSerial.txt b/build/shared/examples/09.USB/Keyboard/KeyboardSerial/KeyboardSerial.txt new file mode 100644 index 000000000..e4e3f91d4 --- /dev/null +++ b/build/shared/examples/09.USB/Keyboard/KeyboardSerial/KeyboardSerial.txt @@ -0,0 +1 @@ +Reads a byte from the serial port, and sends back a keystroke. \ No newline at end of file diff --git a/build/shared/examples/09.USB/KeyboardAndMouseControl/KeyboardAndMouseControl.txt b/build/shared/examples/09.USB/KeyboardAndMouseControl/KeyboardAndMouseControl.txt new file mode 100644 index 000000000..64745d318 --- /dev/null +++ b/build/shared/examples/09.USB/KeyboardAndMouseControl/KeyboardAndMouseControl.txt @@ -0,0 +1 @@ +Demonstrates the Mouse and Keyboard commands in one program. \ No newline at end of file diff --git a/build/shared/examples/09.USB/KeyboardAndMouseControl/layout.png b/build/shared/examples/09.USB/KeyboardAndMouseControl/layout.png new file mode 100644 index 000000000..45fdc9c07 Binary files /dev/null and b/build/shared/examples/09.USB/KeyboardAndMouseControl/layout.png differ diff --git a/build/shared/examples/09.USB/KeyboardAndMouseControl/schematic.png b/build/shared/examples/09.USB/KeyboardAndMouseControl/schematic.png new file mode 100644 index 000000000..09998b07b Binary files /dev/null and b/build/shared/examples/09.USB/KeyboardAndMouseControl/schematic.png differ diff --git a/build/shared/examples/09.USB/Mouse/ButtonMouseControl/ButtonMouseControl.txt b/build/shared/examples/09.USB/Mouse/ButtonMouseControl/ButtonMouseControl.txt new file mode 100644 index 000000000..20355589b --- /dev/null +++ b/build/shared/examples/09.USB/Mouse/ButtonMouseControl/ButtonMouseControl.txt @@ -0,0 +1 @@ +Control cursor movement with 5 pushbuttons. \ No newline at end of file diff --git a/build/shared/examples/09.USB/Mouse/ButtonMouseControl/layout.png b/build/shared/examples/09.USB/Mouse/ButtonMouseControl/layout.png new file mode 100644 index 000000000..45fdc9c07 Binary files /dev/null and b/build/shared/examples/09.USB/Mouse/ButtonMouseControl/layout.png differ diff --git a/build/shared/examples/09.USB/Mouse/ButtonMouseControl/schematic.png b/build/shared/examples/09.USB/Mouse/ButtonMouseControl/schematic.png new file mode 100644 index 000000000..09998b07b Binary files /dev/null and b/build/shared/examples/09.USB/Mouse/ButtonMouseControl/schematic.png differ diff --git a/build/shared/examples/09.USB/Mouse/JoystickMouseControl/JoystickMouseControl.txt b/build/shared/examples/09.USB/Mouse/JoystickMouseControl/JoystickMouseControl.txt new file mode 100644 index 000000000..55fa2bc4c --- /dev/null +++ b/build/shared/examples/09.USB/Mouse/JoystickMouseControl/JoystickMouseControl.txt @@ -0,0 +1 @@ +Controls a computer's cursor movement with a Joystick when a button is pressed. \ No newline at end of file diff --git a/build/shared/examples/09.USB/Mouse/JoystickMouseControl/layout.png b/build/shared/examples/09.USB/Mouse/JoystickMouseControl/layout.png new file mode 100644 index 000000000..95a4e9529 Binary files /dev/null and b/build/shared/examples/09.USB/Mouse/JoystickMouseControl/layout.png differ diff --git a/build/shared/examples/09.USB/Mouse/JoystickMouseControl/schematic.png b/build/shared/examples/09.USB/Mouse/JoystickMouseControl/schematic.png new file mode 100644 index 000000000..ae4ecf122 Binary files /dev/null and b/build/shared/examples/09.USB/Mouse/JoystickMouseControl/schematic.png differ diff --git a/build/shared/lib/about.jpg b/build/shared/lib/about.jpg deleted file mode 100644 index 0b168bba1..000000000 Binary files a/build/shared/lib/about.jpg and /dev/null differ diff --git a/build/shared/lib/about.png b/build/shared/lib/about.png new file mode 100644 index 000000000..6354f097d Binary files /dev/null and b/build/shared/lib/about.png differ diff --git a/build/shared/lib/arduino.png b/build/shared/lib/arduino.png new file mode 100644 index 000000000..28fa03ab7 Binary files /dev/null and b/build/shared/lib/arduino.png differ diff --git a/build/shared/lib/keywords.txt b/build/shared/lib/keywords.txt index e5bc96533..a362fc358 100644 --- a/build/shared/lib/keywords.txt +++ b/build/shared/lib/keywords.txt @@ -1,113 +1,77 @@ -# LITERAL1 specifies constants +#FUNCTIONS COLOR #D35400 - ORANGE KEYWORD1 +#FUNCTIONS COLOR #D35400 - ORANGE KEYWORD2 +#STRUCTURE COLORS #5E6D03 - GREEN KEYWORD3 +#VARIABLES COLOR #00979C - BLUE LITERAL2 -HIGH LITERAL1 Constants -LOW LITERAL1 Constants -INPUT LITERAL1 Constants -INPUT_PULLUP LITERAL1 Constants -OUTPUT LITERAL1 Constants -DEC LITERAL1 Serial_Print -BIN LITERAL1 Serial_Print -HEX LITERAL1 Serial_Print -OCT LITERAL1 Serial_Print -PI LITERAL1 -HALF_PI LITERAL1 -TWO_PI LITERAL1 -LSBFIRST LITERAL1 ShiftOut -MSBFIRST LITERAL1 ShiftOut -CHANGE LITERAL1 AttachInterrupt -FALLING LITERAL1 AttachInterrupt -RISING LITERAL1 AttachInterrupt -DEFAULT LITERAL1 AnalogReference -EXTERNAL LITERAL1 AnalogReference -INTERNAL LITERAL1 AnalogReference -INTERNAL1V1 LITERAL1 AnalogReference -INTERNAL2V56 LITERAL1 AnalogReference +# LITERAL2 specifies constants -# KEYWORD1 specifies datatypes and C/C++ keywords +HIGH LITERAL2 Constants RESERVED_WORD_2 +LOW LITERAL2 Constants RESERVED_WORD_2 +INPUT LITERAL2 Constants RESERVED_WORD_2 +INPUT_PULLUP LITERAL2 Constants RESERVED_WORD_2 +OUTPUT LITERAL2 Constants RESERVED_WORD_2 +DEC LITERAL2 Serial_Print RESERVED_WORD_2 +BIN LITERAL2 Serial_Print RESERVED_WORD_2 +HEX LITERAL2 Serial_Print RESERVED_WORD_2 +OCT LITERAL2 Serial_Print RESERVED_WORD_2 +PI LITERAL2 RESERVED_WORD_2 +HALF_PI LITERAL2 RESERVED_WORD_2 +TWO_PI LITERAL2 RESERVED_WORD_2 +LSBFIRST LITERAL2 ShiftOut RESERVED_WORD_2 +MSBFIRST LITERAL2 ShiftOut RESERVED_WORD_2 +CHANGE LITERAL2 AttachInterrupt RESERVED_WORD_2 +FALLING LITERAL2 AttachInterrupt RESERVED_WORD_2 +RISING LITERAL2 AttachInterrupt RESERVED_WORD_2 +DEFAULT LITERAL2 AnalogReference RESERVED_WORD_2 +EXTERNAL LITERAL2 AnalogReference RESERVED_WORD_2 +INTERNAL LITERAL2 AnalogReference RESERVED_WORD_2 +INTERNAL1V1 LITERAL2 AnalogReference RESERVED_WORD_2 +INTERNAL2V56 LITERAL2 AnalogReference RESERVED_WORD_2 -boolean KEYWORD1 BooleanVariables -break KEYWORD1 Break -byte KEYWORD1 Byte -case KEYWORD1 SwitchCase -char KEYWORD1 Char -class KEYWORD1 -const KEYWORD1 Const -continue KEYWORD1 Continue -default KEYWORD1 SwitchCase -do KEYWORD1 DoWhile -double KEYWORD1 Double -else KEYWORD1 Else -false KEYWORD1 Constants -float KEYWORD1 Float -for KEYWORD1 For -if KEYWORD1 If -int KEYWORD1 Int -long KEYWORD1 Long -new KEYWORD1 -null KEYWORD1 -private KEYWORD1 -protected KEYWORD1 -public KEYWORD1 -register KEYWORD1 -return KEYWORD1 Return -short KEYWORD1 -signed KEYWORD1 -static KEYWORD1 Static -String KEYWORD1 String -switch KEYWORD1 SwitchCase -this KEYWORD1 -throw KEYWORD1 -try KEYWORD1 -true KEYWORD1 -unsigned KEYWORD1 -void KEYWORD1 Void -while KEYWORD1 While -word KEYWORD1 Word +auto LITERAL2 RESERVED_WORD_2 +constexpr LITERAL2 RESERVED_WORD_2 +decltype LITERAL2 RESERVED_WORD_2 +nullptr LITERAL2 RESERVED_WORD_2 +wchar_t LITERAL2 RESERVED_WORD_2 -# operators aren't highlighted, but may have documentation +int8_t LITERAL2 RESERVED_WORD_2 +int16_t LITERAL2 RESERVED_WORD_2 +int32_t LITERAL2 RESERVED_WORD_2 +int64_t LITERAL2 RESERVED_WORD_2 +uint8_t LITERAL2 RESERVED_WORD_2 +uint16_t LITERAL2 RESERVED_WORD_2 +uint32_t LITERAL2 RESERVED_WORD_2 +uint64_t LITERAL2 RESERVED_WORD_2 -+= IncrementCompound -+ Arithmetic -[] arrayaccess -= assign -& BitwiseAnd -| BitwiseAnd -, -// Comments -?: -{} Braces --- Increment -/ Arithmetic -/* Comments -. dot -== -< greaterthan -<= greaterthanorequalto -++ Increment -!= inequality -<< Bitshift -< lessthan -<= lessthanorequalto -&& Boolean -! Boolean -|| Boolean -- Arithmetic -% Modulo -* Arithmetic -() parentheses ->> Bitshift -; SemiColon --= IncrementCompound - -# these are datatypes, but we've also defined functions to cast to them - -boolean KEYWORD2 boolean_ -byte KEYWORD2 byte_ -char KEYWORD2 char_ -float KEYWORD2 float_ -int KEYWORD2 int_ -long KEYWORD2 long_ -word KEYWORD2 word_ +char16_t LITERAL2 RESERVED_WORD_2 +char32_t LITERAL2 RESERVED_WORD_2 +static_assert LITERAL2 RESERVED_WORD_2 +operator LITERAL2 RESERVED_WORD_2 +enum LITERAL2 RESERVED_WORD_2 +delete LITERAL2 RESERVED_WORD_2 +bool LITERAL2 RESERVED_WORD_2 +boolean LITERAL2 BooleanVariables RESERVED_WORD_2 +byte LITERAL2 Byte RESERVED_WORD_2 +char LITERAL2 Char RESERVED_WORD_2 +const LITERAL2 Const RESERVED_WORD_2 +false LITERAL2 Constants LITERAL_BOOLEAN +float LITERAL2 Float RESERVED_WORD_2 +double LITERAL2 RESERVED_WORD_2 +null LITERAL2 RESERVED_WORD_2 +int LITERAL2 Int RESERVED_WORD_2 +long LITERAL2 Long RESERVED_WORD_2 +new LITERAL2 RESERVED_WORD_2 +private LITERAL2 RESERVED_WORD_2 +protected LITERAL2 RESERVED_WORD_2 +public LITERAL2 RESERVED_WORD_2 +short LITERAL2 RESERVED_WORD_2 +signed LITERAL2 RESERVED_WORD_2 +static LITERAL2 Static RESERVED_WORD_2 +String LITERAL2 String RESERVED_WORD_2 +void LITERAL2 Void RESERVED_WORD_2 +true LITERAL2 LITERAL_BOOLEAN +unsigned LITERAL2 RESERVED_WORD_2 +word LITERAL2 RESERVED_WORD_2 # KEYWORD2 specifies methods and functions @@ -165,11 +129,11 @@ shiftOut KEYWORD2 ShiftOut tone KEYWORD2 Tone yield KEYWORD2 Yield -Serial KEYWORD3 Serial -Serial1 KEYWORD3 Serial -Serial2 KEYWORD3 Serial -Serial3 KEYWORD3 Serial -SerialUSB KEYWORD3 Serial +Serial KEYWORD1 Serial DATA_TYPE +Serial1 KEYWORD1 Serial DATA_TYPE +Serial2 KEYWORD1 Serial DATA_TYPE +Serial3 KEYWORD1 Serial DATA_TYPE +SerialUSB KEYWORD1 Serial DATA_TYPE begin KEYWORD2 Serial_Begin end KEYWORD2 Serial_End peek KEYWORD2 Serial_Peek @@ -209,10 +173,8 @@ substring KEYWORD2 toCharArray KEYWORD2 toInt KEYWORD2 -# USB-related keywords - -Keyboard KEYWORD3 -Mouse KEYWORD3 +Keyboard KEYWORD1 DATA_TYPE +Mouse KEYWORD1 DATA_TYPE press KEYWORD2 release KEYWORD2 releaseAll KEYWORD2 @@ -221,5 +183,68 @@ click KEYWORD2 move KEYWORD2 isPressed KEYWORD2 -setup KEYWORD3 Setup -loop KEYWORD3 Loop +# KEYWORD3 specifies structures + +break KEYWORD3 Break RESERVED_WORD +case KEYWORD3 SwitchCase RESERVED_WORD +class KEYWORD3 RESERVED_WORD +continue KEYWORD3 Continue RESERVED_WORD +default KEYWORD3 SwitchCase RESERVED_WORD +do KEYWORD3 DoWhile RESERVED_WORD +else KEYWORD3 Else RESERVED_WORD +for KEYWORD3 For RESERVED_WORD +if KEYWORD3 If RESERVED_WORD +register KEYWORD3 RESERVED_WORD +return KEYWORD3 Return RESERVED_WORD + +switch KEYWORD3 SwitchCase RESERVED_WORD +this KEYWORD3 RESERVED_WORD +throw KEYWORD3 RESERVED_WORD +try KEYWORD3 RESERVED_WORD +while KEYWORD3 While RESERVED_WORD + +setup KEYWORD3 Setup RESERVED_WORD +loop KEYWORD3 Loop RESERVED_WORD + +alignas KEYWORD3 RESERVED_WORD +alignof KEYWORD3 RESERVED_WORD +asm KEYWORD3 RESERVED_WORD +export KEYWORD3 RESERVED_WORD +thread_local KEYWORD3 RESERVED_WORD +noexcept KEYWORD3 RESERVED_WORD +export KEYWORD3 RESERVED_WORD + +# operators aren't highlighted, but may have documentation + ++= IncrementCompound ++ Arithmetic +[] arrayaccess += assign +& BitwiseAnd +| BitwiseAnd +, +// Comments +?: +{} Braces +-- Increment +/ Arithmetic +/* Comments +. dot +== +< greaterthan +<= greaterthanorequalto +++ Increment +!= inequality +<< Bitshift +< lessthan +<= lessthanorequalto +&& Boolean +! Boolean +|| Boolean +- Arithmetic +% Modulo +* Arithmetic +() parentheses +>> Bitshift +; SemiColon +-= DecrementCompound diff --git a/build/shared/lib/preferences.txt b/build/shared/lib/preferences.txt index 5dfde1ce2..edb47ed03 100644 --- a/build/shared/lib/preferences.txt +++ b/build/shared/lib/preferences.txt @@ -86,13 +86,15 @@ editor.window.height.min = 290 # tested to be 515 on Windows XP, this leaves some room #editor.window.height.min.windows = 530 +# Enable code folding +editor.code_folding=false # 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 +editor.font.macosx = Monaco,plain,12 -# anti-aliased text, turned off by default +# anti-aliased text, turned on by default editor.antialias=true # color to be used for background when 'external editor' enabled diff --git a/build/shared/lib/public.gpg.key b/build/shared/lib/public.gpg.key new file mode 100644 index 000000000..5de39fed1 Binary files /dev/null and b/build/shared/lib/public.gpg.key differ diff --git a/build/shared/lib/splash.png b/build/shared/lib/splash.png new file mode 100644 index 000000000..c89206f8c Binary files /dev/null and b/build/shared/lib/splash.png differ diff --git a/build/shared/lib/theme/newwindow.gif b/build/shared/lib/theme/newwindow.gif new file mode 100644 index 000000000..1cf77a620 Binary files /dev/null and b/build/shared/lib/theme/newwindow.gif differ diff --git a/build/shared/lib/theme/syntax/dark.xml b/build/shared/lib/theme/syntax/dark.xml new file mode 100644 index 000000000..c9283f38d --- /dev/null +++ b/build/shared/lib/theme/syntax/dark.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ + \ + \ +

Hello from ESP8266!

\ +

Uptime: %02d:%02d:%02d

\ + \ + \ +", + + hr, min % 60, sec % 60 + ); + server.send ( 200, "text/html", temp ); + digitalWrite ( led, 0 ); +} + +void handleNotFound() { + digitalWrite ( led, 1 ); + String message = "File Not Found\n\n"; + message += "URI: "; + message += server.uri(); + message += "\nMethod: "; + message += ( server.method() == HTTP_GET ) ? "GET" : "POST"; + message += "\nArguments: "; + message += server.args(); + message += "\n"; + + for ( uint8_t i = 0; i < server.args(); i++ ) { + message += " " + server.argName ( i ) + ": " + server.arg ( i ) + "\n"; + } + + server.send ( 404, "text/plain", message ); + digitalWrite ( led, 0 ); +} + +void setup ( void ) { + pinMode ( led, OUTPUT ); + digitalWrite ( led, 0 ); + Serial.begin ( 115200 ); + WiFi.begin ( ssid, password ); + Serial.println ( "" ); + + // Wait for connection + while ( WiFi.status() != WL_CONNECTED ) { + delay ( 500 ); + Serial.print ( "." ); + } + + Serial.println ( "" ); + Serial.print ( "Connected to " ); + Serial.println ( ssid ); + Serial.print ( "IP address: " ); + Serial.println ( WiFi.localIP() ); + + if ( mdns.begin ( "esp8266", WiFi.localIP() ) ) { + Serial.println ( "MDNS responder started" ); + } + + server.on ( "/", handleRoot ); + server.on ( "/test.svg", drawGraph ); + server.on ( "/inline", []() { + server.send ( 200, "text/plain", "this works as well" ); + } ); + server.onNotFound ( handleNotFound ); + server.begin(); + Serial.println ( "HTTP server started" ); +} + +void loop ( void ) { + mdns.update(); + server.handleClient(); +} + +void drawGraph() { + String out = ""; + char temp[100]; + out += "\n"; + out += "\n"; + out += "\n"; + int y = rand() % 130; + for (int x = 10; x < 390; x+= 10) { + int y2 = rand() % 130; + sprintf(temp, "\n", x, 140 - y, x + 10, 140 - y2); + out += temp; + y = y2; + } + out += "\n\n"; + + server.send ( 200, "image/svg+xml", out); +} diff --git a/hardware/esp8266com/esp8266/libraries/ESP8266WebServer/examples/SDWebServer/SDWebServer.ino b/hardware/esp8266com/esp8266/libraries/ESP8266WebServer/examples/SDWebServer/SDWebServer.ino index d9e230c77..d0e4e1d35 100644 --- a/hardware/esp8266com/esp8266/libraries/ESP8266WebServer/examples/SDWebServer/SDWebServer.ino +++ b/hardware/esp8266com/esp8266/libraries/ESP8266WebServer/examples/SDWebServer/SDWebServer.ino @@ -34,7 +34,6 @@ #include #include -#define WWW_BUF_SIZE 1460 #define DBG_OUTPUT_PORT Serial const char* ssid = "**********"; @@ -47,30 +46,17 @@ ESP8266WebServer server(80); static bool hasSD = false; File uploadFile; -void returnOK(){ - WiFiClient client = server.client(); - String message = "HTTP/1.1 200 OK\r\n"; - message += "Content-Type: text/plain\r\n"; - message += "Connection: close\r\n"; - message += "Access-Control-Allow-Origin: *\r\n"; - message += "\r\n"; - client.print(message); - message = 0; - client.stop(); + +void returnOK() { + server.sendHeader("Connection", "close"); + server.sendHeader("Access-Control-Allow-Origin", "*"); + server.send(200, "text/plain", ""); } -void returnFail(String msg){ - WiFiClient client = server.client(); - String message = "HTTP/1.1 500 Fail\r\n"; - message += "Content-Type: text/plain\r\n"; - message += "Connection: close\r\n"; - message += "Access-Control-Allow-Origin: *\r\n"; - message += "\r\n"; - message += msg; - message += "\r\n"; - client.print(message); - message = 0; - client.stop(); +void returnFail(String msg) { + server.sendHeader("Connection", "close"); + server.sendHeader("Access-Control-Allow-Origin", "*"); + server.send(500, "text/plain", msg + "\r\n"); } bool loadFromSdCard(String path){ @@ -95,59 +81,40 @@ bool loadFromSdCard(String path){ dataType = "text/html"; dataFile = SD.open(path.c_str()); } + + if (!dataFile) + return false; if(server.hasArg("download")) dataType = "application/octet-stream"; - if (dataFile) { - WiFiClient client = server.client(); - String head = "HTTP/1.1 200 OK\r\nContent-Type: "; - head += dataType; - head += "\r\nContent-Length: "; - head += dataFile.size(); - head += "\r\nConnection: close"; - head += "\r\nAccess-Control-Allow-Origin: *"; - head += "\r\n\r\n"; - client.print(head); - dataType = 0; - path = 0; - - uint8_t obuf[WWW_BUF_SIZE]; - - while (dataFile.available() > WWW_BUF_SIZE){ - dataFile.read(obuf, WWW_BUF_SIZE); - if(client.write(obuf, WWW_BUF_SIZE) != WWW_BUF_SIZE){ - DBG_OUTPUT_PORT.println("Sent less data than expected!"); - dataFile.close(); - return true; - } - } - uint16_t leftLen = dataFile.available(); - dataFile.read(obuf, leftLen); - if(client.write(obuf, leftLen) != leftLen){ - DBG_OUTPUT_PORT.println("Sent less data than expected!"); - dataFile.close(); - return true; - } - dataFile.close(); - client.stop(); - return true; + server.sendHeader("Content-Length", String(dataFile.size())); + server.sendHeader("Connection", "close"); + server.sendHeader("Access-Control-Allow-Origin", "*"); + server.send(200, dataType.c_str(), ""); + + WiFiClient client = server.client(); + size_t totalSize = dataFile.size(); + if (client.write(dataFile, HTTP_DOWNLOAD_UNIT_SIZE) != totalSize) { + DBG_OUTPUT_PORT.println("Sent less data than expected!"); } - return false; + + dataFile.close(); + return true; } void handleFileUpload(){ if(server.uri() != "/edit") return; - HTTPUpload upload = server.upload(); + HTTPUpload& upload = server.upload(); if(upload.status == UPLOAD_FILE_START){ if(SD.exists((char *)upload.filename.c_str())) SD.remove((char *)upload.filename.c_str()); uploadFile = SD.open(upload.filename.c_str(), FILE_WRITE); DBG_OUTPUT_PORT.print("Upload: START, filename: "); DBG_OUTPUT_PORT.println(upload.filename); } else if(upload.status == UPLOAD_FILE_WRITE){ - if(uploadFile) uploadFile.write(upload.buf, upload.buflen); - DBG_OUTPUT_PORT.print("Upload: WRITE, Bytes: "); DBG_OUTPUT_PORT.println(upload.buflen); + if(uploadFile) uploadFile.write(upload.buf, upload.currentSize); + DBG_OUTPUT_PORT.print("Upload: WRITE, Bytes: "); DBG_OUTPUT_PORT.println(upload.currentSize); } else if(upload.status == UPLOAD_FILE_END){ if(uploadFile) uploadFile.close(); - DBG_OUTPUT_PORT.print("Upload: END, Size: "); DBG_OUTPUT_PORT.println(upload.size); + DBG_OUTPUT_PORT.print("Upload: END, Size: "); DBG_OUTPUT_PORT.println(upload.totalSize); } } @@ -158,13 +125,12 @@ void deleteRecursive(String path){ SD.remove((char *)path.c_str()); return; } + file.rewindDirectory(); - File entry; - String entryPath; while(true) { - entry = file.openNextFile(); + File entry = file.openNextFile(); if (!entry) break; - entryPath = path + "/" +entry.name(); + String entryPath = path + "/" +entry.name(); if(entry.isDirectory()){ entry.close(); deleteRecursive(entryPath); @@ -172,27 +138,32 @@ void deleteRecursive(String path){ entry.close(); SD.remove((char *)entryPath.c_str()); } - entryPath = 0; yield(); } + SD.rmdir((char *)path.c_str()); - path = 0; file.close(); } void handleDelete(){ if(server.args() == 0) return returnFail("BAD ARGS"); String path = server.arg(0); - if(path == "/" || !SD.exists((char *)path.c_str())) return returnFail("BAD PATH"); + if(path == "/" || !SD.exists((char *)path.c_str())) { + returnFail("BAD PATH"); + return; + } deleteRecursive(path); returnOK(); - path = 0; } void handleCreate(){ if(server.args() == 0) return returnFail("BAD ARGS"); String path = server.arg(0); - if(path == "/" || SD.exists((char *)path.c_str())) return returnFail("BAD PATH"); + if(path == "/" || SD.exists((char *)path.c_str())) { + returnFail("BAD PATH"); + return; + } + if(path.indexOf('.') > 0){ File file = SD.open((char *)path.c_str(), FILE_WRITE); if(file){ @@ -203,7 +174,6 @@ void handleCreate(){ SD.mkdir((char *)path.c_str()); } returnOK(); - path = 0; } void printDirectory() { @@ -211,38 +181,38 @@ void printDirectory() { String path = server.arg("dir"); if(path != "/" && !SD.exists((char *)path.c_str())) return returnFail("BAD PATH"); File dir = SD.open((char *)path.c_str()); - path = 0; + path = String(); if(!dir.isDirectory()){ dir.close(); return returnFail("NOT DIR"); } dir.rewindDirectory(); - File entry; + server.send(200, "text/json", ""); WiFiClient client = server.client(); - client.print("HTTP/1.1 200 OK\r\nContent-Type: text/json\r\n\r\n"); - String output = "["; - while(true) { - entry = dir.openNextFile(); - if (!entry) break; - if(output != "[") output += ','; - output += "{\"type\":\""; - output += (entry.isDirectory())?"dir":"file"; - output += "\",\"name\":\""; - output += entry.name(); - output += "\""; - output += "}"; - entry.close(); - if(output.length() > 1460){ - client.write(output.substring(0, 1460).c_str(), 1460); - output = output.substring(1460); - } + + for (int cnt = 0; true; ++cnt) { + File entry = dir.openNextFile(); + if (!entry) + break; + + String output; + if (cnt == 0) + output = '['; + else + output = ','; + + output += "{\"type\":\""; + output += (entry.isDirectory()) ? "dir" : "file"; + output += "\",\"name\":\""; + output += entry.name(); + output += "\""; + output += "}"; + server.sendContent(output); + entry.close(); } + server.sendContent("]"); dir.close(); - output += "]"; - client.write(output.c_str(), output.length()); - client.stop(); - output = 0; } void handleNotFound(){ @@ -282,14 +252,14 @@ void setup(void){ } DBG_OUTPUT_PORT.print("Connected! IP address: "); DBG_OUTPUT_PORT.println(WiFi.localIP()); - /* + if (mdns.begin(hostname, WiFi.localIP())) { DBG_OUTPUT_PORT.println("MDNS responder started"); DBG_OUTPUT_PORT.print("You can now connect to http://"); DBG_OUTPUT_PORT.print(hostname); DBG_OUTPUT_PORT.println(".local"); } - */ + server.on("/list", HTTP_GET, printDirectory); server.on("/edit", HTTP_DELETE, handleDelete); @@ -306,7 +276,7 @@ void setup(void){ hasSD = true; } } - + void loop(void){ server.handleClient(); } diff --git a/hardware/esp8266com/esp8266/libraries/ESP8266WebServer/src/ESP8266WebServer.cpp b/hardware/esp8266com/esp8266/libraries/ESP8266WebServer/src/ESP8266WebServer.cpp index cc4fffcce..391cc556c 100644 --- a/hardware/esp8266com/esp8266/libraries/ESP8266WebServer/src/ESP8266WebServer.cpp +++ b/hardware/esp8266com/esp8266/libraries/ESP8266WebServer/src/ESP8266WebServer.cpp @@ -26,8 +26,8 @@ #include "WiFiClient.h" #include "ESP8266WebServer.h" -//#define DEBUG -#define DEBUG_OUTPUT Serial1 +// #define DEBUG +#define DEBUG_OUTPUT Serial struct ESP8266WebServer::RequestHandler { RequestHandler(ESP8266WebServer::THandlerFunction fn, const char* uri, HTTPMethod method) @@ -99,110 +99,32 @@ void ESP8266WebServer::handleClient() #ifdef DEBUG DEBUG_OUTPUT.println("New client"); #endif + // Wait for data from client to become available while(client.connected() && !client.available()){ delay(1); } - // Read the first line of HTTP request - String req = client.readStringUntil('\r'); - client.readStringUntil('\n'); - - // First line of HTTP request looks like "GET /path HTTP/1.1" - // Retrieve the "/path" part by finding the spaces - int addr_start = req.indexOf(' '); - int addr_end = req.indexOf(' ', addr_start + 1); - if (addr_start == -1 || addr_end == -1) { -#ifdef DEBUG - DEBUG_OUTPUT.print("Invalid request: "); - DEBUG_OUTPUT.println(req); -#endif + if (!_parseRequest(client)) { return; } - - String methodStr = req.substring(0, addr_start); - String url = req.substring(addr_start + 1, addr_end); - String searchStr = ""; - int hasSearch = url.indexOf('?'); - if(hasSearch != -1){ - searchStr = url.substring(hasSearch + 1); - url = url.substring(0, hasSearch); - } - _currentUri = url; - - HTTPMethod method = HTTP_GET; - if (methodStr == "POST") { - method = HTTP_POST; - } else if (methodStr == "DELETE") { - method = HTTP_DELETE; - } else if (methodStr == "PUT") { - method = HTTP_PUT; - } else if (methodStr == "PATCH") { - method = HTTP_PATCH; - } - -#ifdef DEBUG - DEBUG_OUTPUT.print("method: "); - DEBUG_OUTPUT.print(methodStr); - DEBUG_OUTPUT.print(" url: "); - DEBUG_OUTPUT.print(url); - DEBUG_OUTPUT.print(" search: "); - DEBUG_OUTPUT.println(searchStr); -#endif - String formData; - //bellow is needed only when POST type request - if(method == HTTP_POST || method == HTTP_PUT || method == HTTP_PATCH || method == HTTP_DELETE){ - String boundaryStr; - String headerName; - String headerValue; - bool isForm = false; - uint32_t contentLength = 0; - //parse headers - while(1){ - req = client.readStringUntil('\r'); - client.readStringUntil('\n'); - if(req == "") break;//no moar headers - int headerDiv = req.indexOf(':'); - if(headerDiv == -1){ - break; - } - headerName = req.substring(0, headerDiv); - headerValue = req.substring(headerDiv + 2); - if(headerName == "Content-Type"){ - if(headerValue.startsWith("text/plain")){ - isForm = false; - } else if(headerValue.startsWith("multipart/form-data")){ - boundaryStr = headerValue.substring(headerValue.indexOf('=')+1); - isForm = true; - } - } else if(headerName == "Content-Length"){ - contentLength = headerValue.toInt(); - } - } - - if(!isForm){ - if(searchStr != "") searchStr += '&'; - searchStr += client.readStringUntil('\r'); - client.readStringUntil('\n'); - } - _parseArguments(searchStr); - if(isForm){ - _parseForm(client, boundaryStr, contentLength); - } - } else { - _parseArguments(searchStr); + _currentClient = client; + _handleRequest(); +} + +void ESP8266WebServer::sendHeader(String name, String value, bool first) { + String headerLine = name; + headerLine += ": "; + headerLine += value; + headerLine += "\r\n"; + + if (first) { + _responseHeaders = headerLine + _responseHeaders; + } + else { + _responseHeaders += headerLine; } - client.flush(); - -#ifdef DEBUG - DEBUG_OUTPUT.print("Request: "); - DEBUG_OUTPUT.println(url); - DEBUG_OUTPUT.print(" Arguments: "); - DEBUG_OUTPUT.println(searchStr); -#endif - - _handleRequest(client, url, method); } void ESP8266WebServer::send(int code, const char* content_type, String content) { @@ -214,11 +136,28 @@ void ESP8266WebServer::send(int code, const char* content_type, String content) if (!content_type) content_type = "text/html"; - _appendHeader(response, "Content-Type", content_type); + sendHeader("Content-Type", content_type, true); + response += _responseHeaders; response += "\r\n"; response += content; - _currentClient.print(response); + _responseHeaders = String(); + sendContent(response); +} + +void ESP8266WebServer::sendContent(String content) { + size_t size_to_send = content.length(); + size_t size_sent = 0; + while(size_to_send) { + const size_t unit_size = HTTP_DOWNLOAD_UNIT_SIZE; + size_t will_send = (size_to_send < unit_size) ? size_to_send : unit_size; + size_t sent = _currentClient.write(content.c_str() + size_sent, will_send); + size_to_send -= sent; + size_sent += sent; + if (sent == 0) { + break; + } + } } String ESP8266WebServer::arg(const char* name) { @@ -253,298 +192,6 @@ bool ESP8266WebServer::hasArg(const char* name) { return false; } -void ESP8266WebServer::_parseArguments(String data) { -#ifdef DEBUG - DEBUG_OUTPUT.print("args: "); - DEBUG_OUTPUT.println(data); -#endif - if (_currentArgs) - delete[] _currentArgs; - _currentArgs = 0; - if (data.length() == 0) { - _currentArgCount = 0; - return; - } - _currentArgCount = 1; - - for (int i = 0; i < data.length(); ) { - i = data.indexOf('&', i); - if (i == -1) - break; - ++i; - ++_currentArgCount; - } -#ifdef DEBUG - DEBUG_OUTPUT.print("args count: "); - DEBUG_OUTPUT.println(_currentArgCount); -#endif - - _currentArgs = new RequestArgument[_currentArgCount]; - int pos = 0; - int iarg; - for (iarg = 0; iarg < _currentArgCount;) { - int equal_sign_index = data.indexOf('=', pos); - int next_arg_index = data.indexOf('&', pos); -#ifdef DEBUG - DEBUG_OUTPUT.print("pos "); - DEBUG_OUTPUT.print(pos); - DEBUG_OUTPUT.print("=@ "); - DEBUG_OUTPUT.print(equal_sign_index); - DEBUG_OUTPUT.print(" &@ "); - DEBUG_OUTPUT.println(next_arg_index); -#endif - if ((equal_sign_index == -1) || ((equal_sign_index > next_arg_index) && (next_arg_index != -1))) { -#ifdef DEBUG - DEBUG_OUTPUT.print("arg missing value: "); - DEBUG_OUTPUT.println(iarg); -#endif - if (next_arg_index == -1) - break; - pos = next_arg_index + 1; - continue; - } - RequestArgument& arg = _currentArgs[iarg]; - arg.key = data.substring(pos, equal_sign_index); - arg.value = data.substring(equal_sign_index + 1, next_arg_index); -#ifdef DEBUG - DEBUG_OUTPUT.print("arg "); - DEBUG_OUTPUT.print(iarg); - DEBUG_OUTPUT.print(" key: "); - DEBUG_OUTPUT.print(arg.key); - DEBUG_OUTPUT.print(" value: "); - DEBUG_OUTPUT.println(arg.value); -#endif - ++iarg; - if (next_arg_index == -1) - break; - pos = next_arg_index + 1; - } - _currentArgCount = iarg; -#ifdef DEBUG - DEBUG_OUTPUT.print("args count: "); - DEBUG_OUTPUT.println(_currentArgCount); -#endif - -} - -void ESP8266WebServer::_parseForm(WiFiClient& client, String boundary, uint32_t len){ - -#ifdef DEBUG - DEBUG_OUTPUT.print("Parse Form: Boundary: "); - DEBUG_OUTPUT.print(boundary); - DEBUG_OUTPUT.print("Length: "); - DEBUG_OUTPUT.println(len); -#endif - String line; - line = client.readStringUntil('\r'); - client.readStringUntil('\n'); - //start reading the form - if(line == ("--"+boundary)){ - RequestArgument* postArgs = new RequestArgument[32]; - int postArgsLen = 0; - while(1){ - String argName; - String argValue; - String argType; - String argFilename; - bool argIsFile = false; - - line = client.readStringUntil('\r'); - client.readStringUntil('\n'); - if(line.startsWith("Content-Disposition")){ - int nameStart = line.indexOf('='); - if(nameStart != -1){ - argName = line.substring(nameStart+2); - nameStart = argName.indexOf('='); - if(nameStart == -1){ - argName = argName.substring(0, argName.length() - 1); - } else { - argFilename = argName.substring(nameStart+2, argName.length() - 1); - argName = argName.substring(0, argName.indexOf('"')); - argIsFile = true; - #ifdef DEBUG - DEBUG_OUTPUT.print("PostArg FileName: "); - DEBUG_OUTPUT.println(argFilename); - #endif - //use GET to set the filename if uploading using blob - if(argFilename == "blob" && hasArg("filename")) argFilename = arg("filename"); - } - #ifdef DEBUG - DEBUG_OUTPUT.print("PostArg Name: "); - DEBUG_OUTPUT.println(argName); - #endif - argType = "text/plain"; - line = client.readStringUntil('\r'); - client.readStringUntil('\n'); - if(line.startsWith("Content-Type")){ - argType = line.substring(line.indexOf(':')+2); - //skip next line - client.readStringUntil('\r'); - client.readStringUntil('\n'); - } - #ifdef DEBUG - DEBUG_OUTPUT.print("PostArg Type: "); - DEBUG_OUTPUT.println(argType); - #endif - if(!argIsFile){ - while(1){ - line = client.readStringUntil('\r'); - client.readStringUntil('\n'); - if(line.startsWith("--"+boundary)) break; - if(argValue.length() > 0) argValue += "\n"; - argValue += line; - } - #ifdef DEBUG - DEBUG_OUTPUT.print("PostArg Value: "); - DEBUG_OUTPUT.println(argValue); - DEBUG_OUTPUT.println(); - #endif - - RequestArgument& arg = postArgs[postArgsLen++]; - arg.key = argName; - arg.value = argValue; - - if(line == ("--"+boundary+"--")){ - #ifdef DEBUG - DEBUG_OUTPUT.println("Done Parsing POST"); - #endif - break; - } - } else { - _currentUpload.status = UPLOAD_FILE_START; - _currentUpload.name = argName; - _currentUpload.filename = argFilename; - _currentUpload.type = argType; - _currentUpload.size = 0; - _currentUpload.buflen = 0; -#ifdef DEBUG - DEBUG_OUTPUT.print("Start File: "); - DEBUG_OUTPUT.print(_currentUpload.filename); - DEBUG_OUTPUT.print(" Type: "); - DEBUG_OUTPUT.println(_currentUpload.type); -#endif - if(_fileUploadHandler) _fileUploadHandler(); - _currentUpload.status = UPLOAD_FILE_WRITE; - uint8_t argByte = client.read(); -readfile: - while(argByte != 0x0D){ - _currentUpload.buf[_currentUpload.buflen++] = argByte; - if(_currentUpload.buflen == 1460){ - #ifdef DEBUG - DEBUG_OUTPUT.println("Write File: 1460"); - #endif - if(_fileUploadHandler) _fileUploadHandler(); - _currentUpload.size += _currentUpload.buflen; - _currentUpload.buflen = 0; - } - argByte = client.read(); - } - - argByte = client.read(); - if(argByte == 0x0A){ -#ifdef DEBUG - DEBUG_OUTPUT.print("Write File: "); - DEBUG_OUTPUT.println(_currentUpload.buflen); -#endif - if(_fileUploadHandler) _fileUploadHandler(); - _currentUpload.size += _currentUpload.buflen; - _currentUpload.buflen = 0; - - argByte = client.read(); - if((char)argByte != '-'){ - //continue reading the file - _currentUpload.buf[_currentUpload.buflen++] = 0x0D; - _currentUpload.buf[_currentUpload.buflen++] = 0x0A; - goto readfile; - } else { - argByte = client.read(); - if((char)argByte != '-'){ - //continue reading the file - _currentUpload.buf[_currentUpload.buflen++] = 0x0D; - _currentUpload.buf[_currentUpload.buflen++] = 0x0A; - _currentUpload.buf[_currentUpload.buflen++] = (uint8_t)('-'); - goto readfile; - } - } - - uint8_t endBuf[boundary.length()]; - client.readBytes(endBuf, boundary.length()); - - if(strstr((const char*)endBuf, (const char*)(boundary.c_str())) != NULL){ - _currentUpload.status = UPLOAD_FILE_END; -#ifdef DEBUG - DEBUG_OUTPUT.print("End File: "); - DEBUG_OUTPUT.print(_currentUpload.filename); - DEBUG_OUTPUT.print(" Type: "); - DEBUG_OUTPUT.print(_currentUpload.type); - DEBUG_OUTPUT.print(" Size: "); - DEBUG_OUTPUT.println(_currentUpload.size); -#endif - if(_fileUploadHandler) _fileUploadHandler(); - line = client.readStringUntil(0x0D); - client.readStringUntil(0x0A); - if(line == "--"){ -#ifdef DEBUG - DEBUG_OUTPUT.println("Done Parsing POST"); -#endif - break; - } - continue; - } else { - _currentUpload.buf[_currentUpload.buflen++] = 0x0D; - _currentUpload.buf[_currentUpload.buflen++] = 0x0A; - uint32_t i = 0; - while(i < boundary.length()){ - _currentUpload.buf[_currentUpload.buflen++] = endBuf[i++]; - if(_currentUpload.buflen == 1460){ -#ifdef DEBUG - DEBUG_OUTPUT.println("Write File: 1460"); -#endif - if(_fileUploadHandler) _fileUploadHandler(); - _currentUpload.size += _currentUpload.buflen; - _currentUpload.buflen = 0; - } - } - argByte = client.read(); - goto readfile; - } - } else { - _currentUpload.buf[_currentUpload.buflen++] = 0x0D; - if(_currentUpload.buflen == 1460){ - #ifdef DEBUG - DEBUG_OUTPUT.println("Write File: 1460"); - #endif - if(_fileUploadHandler) _fileUploadHandler(); - _currentUpload.size += _currentUpload.buflen; - _currentUpload.buflen = 0; - } - goto readfile; - } - break; - } - } - } - } - - int iarg; - int totalArgs = ((32 - postArgsLen) < _currentArgCount)?(32 - postArgsLen):_currentArgCount; - for (iarg = 0; iarg < totalArgs; iarg++){ - RequestArgument& arg = postArgs[postArgsLen++]; - arg.key = _currentArgs[iarg].key; - arg.value = _currentArgs[iarg].value; - } - if (_currentArgs) delete[] _currentArgs; - _currentArgs = new RequestArgument[postArgsLen]; - for (iarg = 0; iarg < postArgsLen; iarg++){ - RequestArgument& arg = _currentArgs[iarg]; - arg.key = postArgs[iarg].key; - arg.value = postArgs[iarg].value; - } - _currentArgCount = iarg; - if (postArgs) delete[] postArgs; - } -} - void ESP8266WebServer::onFileUpload(THandlerFunction fn) { _fileUploadHandler = fn; } @@ -553,18 +200,14 @@ void ESP8266WebServer::onNotFound(THandlerFunction fn) { _notFoundHandler = fn; } -void ESP8266WebServer::_handleRequest(WiFiClient& client, String uri, HTTPMethod method) { - _currentClient = client; - _currentUri = uri; - _currentMethod = method; - +void ESP8266WebServer::_handleRequest() { RequestHandler* handler; for (handler = _firstHandler; handler; handler = handler->next) { - if (handler->method != HTTP_ANY && handler->method != method) + if (handler->method != HTTP_ANY && handler->method != _currentMethod) continue; - if (handler->uri != uri) + if (handler->uri != _currentUri) continue; handler->fn(); @@ -580,26 +223,19 @@ void ESP8266WebServer::_handleRequest(WiFiClient& client, String uri, HTTPMethod _notFoundHandler(); } else { - send(404, "text/plain", String("Not found: ") + uri); + send(404, "text/plain", String("Not found: ") + _currentUri); } } _currentClient = WiFiClient(); _currentUri = String(); - } const char* ESP8266WebServer::_responseCodeToString(int code) { switch (code) { case 200: return "OK"; case 404: return "Not found"; + case 500: return "Fail"; default: return ""; } } - -void ESP8266WebServer::_appendHeader(String& response, const char* name, const char* value) { - response += name; - response += ": "; - response += value; - response += "\r\n"; -} diff --git a/hardware/esp8266com/esp8266/libraries/ESP8266WebServer/src/ESP8266WebServer.h b/hardware/esp8266com/esp8266/libraries/ESP8266WebServer/src/ESP8266WebServer.h index 423fc6173..d957e15ba 100644 --- a/hardware/esp8266com/esp8266/libraries/ESP8266WebServer/src/ESP8266WebServer.h +++ b/hardware/esp8266com/esp8266/libraries/ESP8266WebServer/src/ESP8266WebServer.h @@ -29,20 +29,22 @@ enum HTTPMethod { HTTP_ANY, HTTP_GET, HTTP_POST, HTTP_PUT, HTTP_PATCH, HTTP_DELETE }; enum HTTPUploadStatus { UPLOAD_FILE_START, UPLOAD_FILE_WRITE, UPLOAD_FILE_END }; +#define HTTP_DOWNLOAD_UNIT_SIZE 1460 +#define HTTP_UPLOAD_BUFLEN 2048 + typedef struct { HTTPUploadStatus status; - String filename; - String name; - String type; - size_t size; - size_t buflen; - uint8_t buf[1460]; + String filename; + String name; + String type; + size_t totalSize; // file size + size_t currentSize; // size of data currently in buf + uint8_t buf[HTTP_UPLOAD_BUFLEN]; } HTTPUpload; class ESP8266WebServer { public: - ESP8266WebServer(int port = 80); ~ESP8266WebServer(); @@ -58,7 +60,7 @@ public: String uri() { return _currentUri; } HTTPMethod method() { return _currentMethod; } WiFiClient client() { return _currentClient; } - HTTPUpload upload() { return _currentUpload; } + HTTPUpload& upload() { return _currentUpload; } String arg(const char* name); // get request argument value by name String arg(int i); // get request argument value by number @@ -72,12 +74,30 @@ public: // content - actual content body void send(int code, const char* content_type = NULL, String content = String("")); + void sendHeader(String name, String value, bool first = false); + void sendContent(String content); + +template size_t streamFile(T &file, String contentType){ + String head = "HTTP/1.1 200 OK\r\nContent-Type: "; + head += contentType; + head += "\r\nContent-Length: "; + head += file.size(); + head += "\r\nConnection: close"; + head += "\r\nAccess-Control-Allow-Origin: *"; + head += "\r\n\r\n"; + _currentClient.print(head); + head = String(); + return _currentClient.write(file, HTTP_DOWNLOAD_UNIT_SIZE); +} + protected: - void _handleRequest(WiFiClient& client, String uri, HTTPMethod method); + void _handleRequest(); + bool _parseRequest(WiFiClient& client); void _parseArguments(String data); static const char* _responseCodeToString(int code); - static void _appendHeader(String& response, const char* name, const char* value); void _parseForm(WiFiClient& client, String boundary, uint32_t len); + void _uploadWriteByte(uint8_t b); + uint8_t _uploadReadByte(WiFiClient& client); struct RequestHandler; struct RequestArgument { @@ -95,6 +115,8 @@ protected: RequestArgument* _currentArgs; HTTPUpload _currentUpload; + String _responseHeaders; + RequestHandler* _firstHandler; RequestHandler* _lastHandler; THandlerFunction _notFoundHandler; diff --git a/hardware/esp8266com/esp8266/libraries/ESP8266WebServer/src/Parsing.cpp b/hardware/esp8266com/esp8266/libraries/ESP8266WebServer/src/Parsing.cpp new file mode 100644 index 000000000..40a58d24a --- /dev/null +++ b/hardware/esp8266com/esp8266/libraries/ESP8266WebServer/src/Parsing.cpp @@ -0,0 +1,417 @@ +/* + Parsing.cpp - HTTP request parsing. + + Copyright (c) 2015 Ivan Grokhotkov. All rights reserved. + + 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Modified 8 May 2015 by Hristo Gochkov (proper post and file upload handling) +*/ + +#include +#include "WiFiServer.h" +#include "WiFiClient.h" +#include "ESP8266WebServer.h" + +// #define DEBUG +#define DEBUG_OUTPUT Serial1 + +bool ESP8266WebServer::_parseRequest(WiFiClient& client) { + // Read the first line of HTTP request + String req = client.readStringUntil('\r'); + client.readStringUntil('\n'); + + // First line of HTTP request looks like "GET /path HTTP/1.1" + // Retrieve the "/path" part by finding the spaces + int addr_start = req.indexOf(' '); + int addr_end = req.indexOf(' ', addr_start + 1); + if (addr_start == -1 || addr_end == -1) { +#ifdef DEBUG + DEBUG_OUTPUT.print("Invalid request: "); + DEBUG_OUTPUT.println(req); +#endif + return false; + } + + String methodStr = req.substring(0, addr_start); + String url = req.substring(addr_start + 1, addr_end); + String searchStr = ""; + int hasSearch = url.indexOf('?'); + if (hasSearch != -1){ + searchStr = url.substring(hasSearch + 1); + url = url.substring(0, hasSearch); + } + _currentUri = url; + + HTTPMethod method = HTTP_GET; + if (methodStr == "POST") { + method = HTTP_POST; + } else if (methodStr == "DELETE") { + method = HTTP_DELETE; + } else if (methodStr == "PUT") { + method = HTTP_PUT; + } else if (methodStr == "PATCH") { + method = HTTP_PATCH; + } + _currentMethod = method; + +#ifdef DEBUG + DEBUG_OUTPUT.print("method: "); + DEBUG_OUTPUT.print(methodStr); + DEBUG_OUTPUT.print(" url: "); + DEBUG_OUTPUT.print(url); + DEBUG_OUTPUT.print(" search: "); + DEBUG_OUTPUT.println(searchStr); +#endif + + String formData; + // below is needed only when POST type request + if (method == HTTP_POST || method == HTTP_PUT || method == HTTP_PATCH || method == HTTP_DELETE){ + String boundaryStr; + String headerName; + String headerValue; + bool isForm = false; + uint32_t contentLength = 0; + //parse headers + while(1){ + req = client.readStringUntil('\r'); + client.readStringUntil('\n'); + if (req == "") break;//no moar headers + int headerDiv = req.indexOf(':'); + if (headerDiv == -1){ + break; + } + headerName = req.substring(0, headerDiv); + headerValue = req.substring(headerDiv + 2); + if (headerName == "Content-Type"){ + if (headerValue.startsWith("text/plain")){ + isForm = false; + } else if (headerValue.startsWith("multipart/form-data")){ + boundaryStr = headerValue.substring(headerValue.indexOf('=')+1); + isForm = true; + } + } else if (headerName == "Content-Length"){ + contentLength = headerValue.toInt(); + } + } + + if (!isForm){ + if (searchStr != "") searchStr += '&'; + searchStr += client.readStringUntil('\r'); + client.readStringUntil('\n'); + } + _parseArguments(searchStr); + if (isForm){ + _parseForm(client, boundaryStr, contentLength); + } + } else { + _parseArguments(searchStr); + } + client.flush(); + +#ifdef DEBUG + DEBUG_OUTPUT.print("Request: "); + DEBUG_OUTPUT.println(url); + DEBUG_OUTPUT.print(" Arguments: "); + DEBUG_OUTPUT.println(searchStr); +#endif + + return true; +} + + +void ESP8266WebServer::_parseArguments(String data) { +#ifdef DEBUG + DEBUG_OUTPUT.print("args: "); + DEBUG_OUTPUT.println(data); +#endif + if (_currentArgs) + delete[] _currentArgs; + _currentArgs = 0; + if (data.length() == 0) { + _currentArgCount = 0; + return; + } + _currentArgCount = 1; + + for (int i = 0; i < data.length(); ) { + i = data.indexOf('&', i); + if (i == -1) + break; + ++i; + ++_currentArgCount; + } +#ifdef DEBUG + DEBUG_OUTPUT.print("args count: "); + DEBUG_OUTPUT.println(_currentArgCount); +#endif + + _currentArgs = new RequestArgument[_currentArgCount]; + int pos = 0; + int iarg; + for (iarg = 0; iarg < _currentArgCount;) { + int equal_sign_index = data.indexOf('=', pos); + int next_arg_index = data.indexOf('&', pos); +#ifdef DEBUG + DEBUG_OUTPUT.print("pos "); + DEBUG_OUTPUT.print(pos); + DEBUG_OUTPUT.print("=@ "); + DEBUG_OUTPUT.print(equal_sign_index); + DEBUG_OUTPUT.print(" &@ "); + DEBUG_OUTPUT.println(next_arg_index); +#endif + if ((equal_sign_index == -1) || ((equal_sign_index > next_arg_index) && (next_arg_index != -1))) { +#ifdef DEBUG + DEBUG_OUTPUT.print("arg missing value: "); + DEBUG_OUTPUT.println(iarg); +#endif + if (next_arg_index == -1) + break; + pos = next_arg_index + 1; + continue; + } + RequestArgument& arg = _currentArgs[iarg]; + arg.key = data.substring(pos, equal_sign_index); + arg.value = data.substring(equal_sign_index + 1, next_arg_index); +#ifdef DEBUG + DEBUG_OUTPUT.print("arg "); + DEBUG_OUTPUT.print(iarg); + DEBUG_OUTPUT.print(" key: "); + DEBUG_OUTPUT.print(arg.key); + DEBUG_OUTPUT.print(" value: "); + DEBUG_OUTPUT.println(arg.value); +#endif + ++iarg; + if (next_arg_index == -1) + break; + pos = next_arg_index + 1; + } + _currentArgCount = iarg; +#ifdef DEBUG + DEBUG_OUTPUT.print("args count: "); + DEBUG_OUTPUT.println(_currentArgCount); +#endif + +} + +void ESP8266WebServer::_uploadWriteByte(uint8_t b){ + if (_currentUpload.currentSize == HTTP_UPLOAD_BUFLEN){ + if (_fileUploadHandler) _fileUploadHandler(); + _currentUpload.totalSize += _currentUpload.currentSize; + _currentUpload.currentSize = 0; + } + _currentUpload.buf[_currentUpload.currentSize++] = b; +} + +uint8_t ESP8266WebServer::_uploadReadByte(WiFiClient& client){ + int res = client.read(); + if(res == -1){ + while(!client.available()) + yield(); + res = client.read(); + } + return (uint8_t)res; +} + +void ESP8266WebServer::_parseForm(WiFiClient& client, String boundary, uint32_t len){ + +#ifdef DEBUG + DEBUG_OUTPUT.print("Parse Form: Boundary: "); + DEBUG_OUTPUT.print(boundary); + DEBUG_OUTPUT.print(" Length: "); + DEBUG_OUTPUT.println(len); +#endif + String line; + line = client.readStringUntil('\r'); + client.readStringUntil('\n'); + //start reading the form + if (line == ("--"+boundary)){ + RequestArgument* postArgs = new RequestArgument[32]; + int postArgsLen = 0; + while(1){ + String argName; + String argValue; + String argType; + String argFilename; + bool argIsFile = false; + + line = client.readStringUntil('\r'); + client.readStringUntil('\n'); + if (line.startsWith("Content-Disposition")){ + int nameStart = line.indexOf('='); + if (nameStart != -1){ + argName = line.substring(nameStart+2); + nameStart = argName.indexOf('='); + if (nameStart == -1){ + argName = argName.substring(0, argName.length() - 1); + } else { + argFilename = argName.substring(nameStart+2, argName.length() - 1); + argName = argName.substring(0, argName.indexOf('"')); + argIsFile = true; +#ifdef DEBUG + DEBUG_OUTPUT.print("PostArg FileName: "); + DEBUG_OUTPUT.println(argFilename); +#endif + //use GET to set the filename if uploading using blob + if (argFilename == "blob" && hasArg("filename")) argFilename = arg("filename"); + } +#ifdef DEBUG + DEBUG_OUTPUT.print("PostArg Name: "); + DEBUG_OUTPUT.println(argName); +#endif + argType = "text/plain"; + line = client.readStringUntil('\r'); + client.readStringUntil('\n'); + if (line.startsWith("Content-Type")){ + argType = line.substring(line.indexOf(':')+2); + //skip next line + client.readStringUntil('\r'); + client.readStringUntil('\n'); + } +#ifdef DEBUG + DEBUG_OUTPUT.print("PostArg Type: "); + DEBUG_OUTPUT.println(argType); +#endif + if (!argIsFile){ + while(1){ + line = client.readStringUntil('\r'); + client.readStringUntil('\n'); + if (line.startsWith("--"+boundary)) break; + if (argValue.length() > 0) argValue += "\n"; + argValue += line; + } +#ifdef DEBUG + DEBUG_OUTPUT.print("PostArg Value: "); + DEBUG_OUTPUT.println(argValue); + DEBUG_OUTPUT.println(); +#endif + + RequestArgument& arg = postArgs[postArgsLen++]; + arg.key = argName; + arg.value = argValue; + + if (line == ("--"+boundary+"--")){ +#ifdef DEBUG + DEBUG_OUTPUT.println("Done Parsing POST"); +#endif + break; + } + } else { + _currentUpload.status = UPLOAD_FILE_START; + _currentUpload.name = argName; + _currentUpload.filename = argFilename; + _currentUpload.type = argType; + _currentUpload.totalSize = 0; + _currentUpload.currentSize = 0; +#ifdef DEBUG + DEBUG_OUTPUT.print("Start File: "); + DEBUG_OUTPUT.print(_currentUpload.filename); + DEBUG_OUTPUT.print(" Type: "); + DEBUG_OUTPUT.println(_currentUpload.type); +#endif + if (_fileUploadHandler) _fileUploadHandler(); + _currentUpload.status = UPLOAD_FILE_WRITE; + uint8_t argByte = _uploadReadByte(client); +readfile: + while(argByte != 0x0D){ + _uploadWriteByte(argByte); + argByte = _uploadReadByte(client); + } + + argByte = _uploadReadByte(client); + if (argByte == 0x0A){ + argByte = _uploadReadByte(client); + if ((char)argByte != '-'){ + //continue reading the file + _uploadWriteByte(0x0D); + _uploadWriteByte(0x0A); + goto readfile; + } else { + argByte = _uploadReadByte(client); + if ((char)argByte != '-'){ + //continue reading the file + _uploadWriteByte(0x0D); + _uploadWriteByte(0x0A); + _uploadWriteByte((uint8_t)('-')); + goto readfile; + } + } + + uint8_t endBuf[boundary.length()]; + client.readBytes(endBuf, boundary.length()); + + if (strstr((const char*)endBuf, boundary.c_str()) != NULL){ + if (_fileUploadHandler) _fileUploadHandler(); + _currentUpload.totalSize += _currentUpload.currentSize; + _currentUpload.status = UPLOAD_FILE_END; + if (_fileUploadHandler) _fileUploadHandler(); +#ifdef DEBUG + DEBUG_OUTPUT.print("End File: "); + DEBUG_OUTPUT.print(_currentUpload.filename); + DEBUG_OUTPUT.print(" Type: "); + DEBUG_OUTPUT.print(_currentUpload.type); + DEBUG_OUTPUT.print(" Size: "); + DEBUG_OUTPUT.println(_currentUpload.totalSize); +#endif + line = client.readStringUntil(0x0D); + client.readStringUntil(0x0A); + if (line == "--"){ +#ifdef DEBUG + DEBUG_OUTPUT.println("Done Parsing POST"); +#endif + break; + } + continue; + } else { + _uploadWriteByte(0x0D); + _uploadWriteByte(0x0A); + _uploadWriteByte((uint8_t)('-')); + _uploadWriteByte((uint8_t)('-')); + uint32_t i = 0; + while(i < boundary.length()){ + _uploadWriteByte(endBuf[i++]); + } + argByte = _uploadReadByte(client); + goto readfile; + } + } else { + _uploadWriteByte(0x0D); + goto readfile; + } + break; + } + } + } + } + + int iarg; + int totalArgs = ((32 - postArgsLen) < _currentArgCount)?(32 - postArgsLen):_currentArgCount; + for (iarg = 0; iarg < totalArgs; iarg++){ + RequestArgument& arg = postArgs[postArgsLen++]; + arg.key = _currentArgs[iarg].key; + arg.value = _currentArgs[iarg].value; + } + if (_currentArgs) delete[] _currentArgs; + _currentArgs = new RequestArgument[postArgsLen]; + for (iarg = 0; iarg < postArgsLen; iarg++){ + RequestArgument& arg = _currentArgs[iarg]; + arg.key = postArgs[iarg].key; + arg.value = postArgs[iarg].value; + } + _currentArgCount = iarg; + if (postArgs) delete[] postArgs; + } +} + + diff --git a/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/examples/WiFiAccessPoint/WiFiAccessPoint.ino b/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/examples/WiFiAccessPoint/WiFiAccessPoint.ino new file mode 100644 index 000000000..9bd390064 --- /dev/null +++ b/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/examples/WiFiAccessPoint/WiFiAccessPoint.ino @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2015, Majenko Technologies + * 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 Majenko Technologies 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Create a WiFi access point and provide a web server on it. */ + +#include +#include +#include + +/* Set these to your desired credentials. */ +const char *ssid = "ESPap"; +const char *password = "thereisnospoon"; + +ESP8266WebServer server(80); + +/* Just a little test message. Go to http://192.168.4.1 in a web browser + * connected to this access point to see it. + */ +void handleRoot() { + server.send(200, "text/html", "

You are connected

"); +} + +void setup() { + delay(1000); + Serial.begin(115200); + Serial.println(); + Serial.print("Configuring access point..."); + /* You can remove the password parameter if you want the AP to be open. */ + WiFi.softAP(ssid, password); + + while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } + + Serial.println("done"); + IPAddress myIP = WiFi.softAPIP(); + Serial.print("AP IP address: "); + Serial.println(myIP); + server.on("/", handleRoot); + server.begin(); + Serial.println("HTTP server started"); +} + +void loop() { + server.handleClient(); +} diff --git a/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/examples/WiFiMulti/WiFiMulti.ino b/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/examples/WiFiMulti/WiFiMulti.ino new file mode 100644 index 000000000..70803254d --- /dev/null +++ b/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/examples/WiFiMulti/WiFiMulti.ino @@ -0,0 +1,33 @@ +/* + * This sketch trys to Connect to the best AP based on a given list + * + */ + +#include +#include + +ESP8266WiFiMulti wifiMulti; + +void setup() { + Serial.begin(115200); + delay(10); + + wifiMulti.addAP("ssid_from_AP_1", "your_password_for_AP_1"); + wifiMulti.addAP("ssid_from_AP_2", "your_password_for_AP_2"); + wifiMulti.addAP("ssid_from_AP_3", "your_password_for_AP_3"); + + Serial.println("Connecting Wifi..."); + if(wifiMulti.run() == WL_CONNECTED) { + Serial.println(""); + Serial.println("WiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + } +} + +void loop() { + if(wifiMulti.run() != WL_CONNECTED) { + Serial.println("WiFi not connected!"); + delay(1000); + } +} \ No newline at end of file diff --git a/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/ESP8266WiFi.cpp b/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/ESP8266WiFi.cpp index caf63982c..115b23763 100644 --- a/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/ESP8266WiFi.cpp +++ b/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/ESP8266WiFi.cpp @@ -81,6 +81,14 @@ int ESP8266WiFiClass::begin(const char* ssid, const char *passphrase) return status(); } +uint8_t ESP8266WiFiClass::waitForConnectResult(){ + if ((wifi_get_opmode() & 1) == 0)//1 and 3 have STA enabled + return WL_DISCONNECTED; + while (status() == WL_DISCONNECTED) + delay(100); + return status(); +} + void ESP8266WiFiClass::config(IPAddress local_ip, IPAddress gateway, IPAddress subnet) { struct ip_info info; @@ -336,7 +344,7 @@ uint8_t ESP8266WiFiClass::encryptionType(uint8_t i) return -1; } -uint8_t ESP8266WiFiClass::status() +wl_status_t ESP8266WiFiClass::status() { int status = wifi_station_get_connect_status(); diff --git a/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/ESP8266WiFi.h b/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/ESP8266WiFi.h index c98f32b8b..feb18abf8 100644 --- a/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/ESP8266WiFi.h +++ b/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/ESP8266WiFi.h @@ -58,6 +58,10 @@ public: */ int begin(const char* ssid, const char *passphrase); + /* Wait for Wifi connection to reach a result + * returns the status reached or disconnect if STA is off + */ + uint8_t waitForConnectResult(); /* Set up an open access point * @@ -195,7 +199,7 @@ public: * * return: one of the value defined in wl_status_t */ - uint8_t status(); + wl_status_t status(); /* * Resolve the given hostname to an IP address. diff --git a/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp b/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp new file mode 100644 index 000000000..3b878020f --- /dev/null +++ b/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp @@ -0,0 +1,171 @@ +/** + * + * @file ESP8266WiFiMulti.cpp + * @date 16.05.2015 + * @author Markus Sattler + * + * Copyright (c) 2015 Markus Sattler. All rights reserved. + * This file is part of the esp8266 core for Arduino environment. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "ESP8266WiFiMulti.h" +#include + +ESP8266WiFiMulti::ESP8266WiFiMulti() { +} + +ESP8266WiFiMulti::~ESP8266WiFiMulti() { + APlistClean(); +} + +bool ESP8266WiFiMulti::addAP(const char* ssid, const char *passphrase) { + return APlistAdd(ssid, passphrase); +} + +wl_status_t ESP8266WiFiMulti::run(void) { + + wl_status_t status = WiFi.status(); + if(status == WL_DISCONNECTED || status == WL_NO_SSID_AVAIL || status == WL_IDLE_STATUS || status == WL_CONNECT_FAILED) { + + WifiAPlist_t bestNetwork { NULL, NULL }; + int bestNetworkDb = INT_MIN; + + // WiFi.scanNetworks will return the number of networks found + int8_t n = WiFi.scanNetworks(); + + DEBUG_WIFI_MULTI("[WIFI] scan done\n"); + delay(0); + + if(n <= 0) { + DEBUG_WIFI_MULTI("[WIFI] no networks found\n"); + } else { + DEBUG_WIFI_MULTI("[WIFI] %d networks found\n", n); + for(int8_t i = 0; i < n; ++i) { + const char * ssid_scan = WiFi.SSID(i); + int32_t rssi_scan = WiFi.RSSI(i); + uint8_t sec_scan = WiFi.encryptionType(i); + + bool known = false; + for(uint32_t x = 0; x < APlist.size(); x++) { + WifiAPlist_t entry = APlist[x]; + + if(strcmp(entry.ssid, ssid_scan) == 0) { // SSID match + known = true; + if(rssi_scan > bestNetworkDb) { // best network + if(sec_scan == ENC_TYPE_NONE || entry.passphrase) { // check for passphrase if not open wlan + bestNetworkDb = rssi_scan; + memcpy((void*) &bestNetwork, (void*) &entry, sizeof(bestNetwork)); + } + } + break; + } + } + + if(known) { + DEBUG_WIFI_MULTI(" ---> "); + } else { + DEBUG_WIFI_MULTI(" "); + } + + DEBUG_WIFI_MULTI(" %d: %s (%d) %c\n", i, ssid_scan, rssi_scan, (sec_scan == ENC_TYPE_NONE) ? ' ' : '*'); + delay(0); + } + } + + DEBUG_WIFI_MULTI("\n\n"); + delay(0); + + if(bestNetwork.ssid) { + DEBUG_WIFI_MULTI("[WIFI] Connecting SSID: %s (%d)\n", bestNetwork.ssid, bestNetworkDb); + + WiFi.begin(bestNetwork.ssid, bestNetwork.passphrase); + status = WiFi.status(); + + // wait for connection or fail + while(status != WL_CONNECTED && status != WL_NO_SSID_AVAIL && status != WL_CONNECT_FAILED) { + delay(10); + status = WiFi.status(); + } + + IPAddress ip; + switch(status) { + case WL_CONNECTED: + ip = WiFi.localIP(); + DEBUG_WIFI_MULTI("[WIFI] Connecting done.\n"); + DEBUG_WIFI_MULTI("[WIFI] SSID: %s\n", WiFi.SSID()); + DEBUG_WIFI_MULTI("[WIFI] IP: %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]); + break; + case WL_NO_SSID_AVAIL: + DEBUG_WIFI_MULTI("[WIFI] Connecting Faild AP not found.\n"); + break; + case WL_CONNECT_FAILED: + DEBUG_WIFI_MULTI("[WIFI] Connecting Faild.\n"); + break; + default: + DEBUG_WIFI_MULTI("[WIFI] Connecting Faild (%d).\n", status); + break; + } + } else { + DEBUG_WIFI_MULTI("[WIFI] no matching wifi found!\n"); + } + } + return status; +} + +// ################################################################################## + +bool ESP8266WiFiMulti::APlistAdd(const char* ssid, const char *passphrase) { + + WifiAPlist_t newAP; + + newAP.ssid = (char*) malloc(strlen(ssid)); + + if(!newAP.ssid) { + return false; + } + + strcpy(newAP.ssid, ssid); + + if(passphrase && *passphrase != 0x00) { + newAP.passphrase = (char*) malloc(strlen(passphrase)); + } + + if(!newAP.passphrase) { + free(newAP.ssid); + return false; + } + + strcpy(newAP.passphrase, passphrase); + + APlist.push_back(newAP); + return true; +} + +void ESP8266WiFiMulti::APlistClean(void) { + for(uint32_t i = 0; i < APlist.size(); i++) { + WifiAPlist_t entry = APlist[i]; + if(entry.ssid) { + free(entry.ssid); + } + if(entry.passphrase) { + free(entry.passphrase); + } + } + APlist.clear(); +} + diff --git a/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.h b/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.h new file mode 100644 index 000000000..9a412ebb1 --- /dev/null +++ b/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.h @@ -0,0 +1,62 @@ +/** + * + * @file ESP8266WiFiMulti.h + * @date 16.05.2015 + * @author Markus Sattler + * + * Copyright (c) 2015 Markus Sattler. All rights reserved. + * This file is part of the esp8266 core for Arduino environment. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + + +#ifndef WIFICLIENTMULTI_H_ +#define WIFICLIENTMULTI_H_ + +#include "ESP8266WiFi.h" +#undef min +#undef max +#include + +//#define DEBUG_WIFI_MULTI(...) os_printf( __VA_ARGS__ ) + +#ifndef DEBUG_WIFI_MULTI +#define DEBUG_WIFI_MULTI(...) +#endif + +typedef struct { + char * ssid; + char * passphrase; +} WifiAPlist_t; + +class ESP8266WiFiMulti { + public: + ESP8266WiFiMulti(); + ~ESP8266WiFiMulti(); + + bool addAP(const char* ssid, const char *passphrase = NULL); + + wl_status_t run(void); + + private: + std::vector APlist; + bool APlistAdd(const char* ssid, const char *passphrase = NULL); + void APlistClean(void); + +}; + +#endif /* WIFICLIENTMULTI_H_ */ diff --git a/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/WiFiClient.cpp b/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/WiFiClient.cpp index 707e486cc..534c7fa89 100644 --- a/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/WiFiClient.cpp +++ b/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/WiFiClient.cpp @@ -123,6 +123,19 @@ void ICACHE_FLASH_ATTR WiFiClient::_err(int8_t err) esp_schedule(); } + +void ICACHE_FLASH_ATTR WiFiClient::setNoDelay(bool nodelay) { + if (!_client) + return; + _client->setNoDelay(nodelay); +} + +bool ICACHE_FLASH_ATTR WiFiClient::getNoDelay() { + if (!_client) + return false; + return _client->getNoDelay(); +} + size_t ICACHE_FLASH_ATTR WiFiClient::write(uint8_t b) { return write(&b, 1); diff --git a/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/WiFiClient.h b/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/WiFiClient.h index 251f2b3e3..f4063cbba 100644 --- a/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/WiFiClient.h +++ b/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/WiFiClient.h @@ -25,6 +25,7 @@ #include "Print.h" #include "Client.h" #include "IPAddress.h" +#include class ClientContext; class WiFiServer; @@ -44,6 +45,9 @@ public: virtual int connect(const char *host, uint16_t port); virtual size_t write(uint8_t); virtual size_t write(const uint8_t *buf, size_t size); + template + size_t write(T& source, size_t unitSize); + virtual int available(); virtual int read(); virtual int read(uint8_t *buf, size_t size); @@ -55,6 +59,30 @@ public: IPAddress remoteIP(); uint16_t remotePort(); + bool getNoDelay(); + void setNoDelay(bool nodelay); + + template size_t write(T &src){ + uint8_t obuf[1460]; + size_t doneLen = 0; + size_t sentLen; + int i; + + while (src.available() > 1460){ + src.read(obuf, 1460); + sentLen = write(obuf, 1460); + doneLen = doneLen + sentLen; + if(sentLen != 1460){ + return doneLen; + } + } + + uint16_t leftLen = src.available(); + src.read(obuf, leftLen); + sentLen = write(obuf, leftLen); + doneLen = doneLen + sentLen; + return doneLen; + } friend class WiFiServer; @@ -72,4 +100,24 @@ private: }; + +template +inline size_t WiFiClient::write(T& source, size_t unitSize) { + std::unique_ptr buffer(new uint8_t[unitSize]); + size_t size_sent = 0; + while(true) { + size_t left = source.available(); + if (!left) + break; + size_t will_send = (left < unitSize) ? left : unitSize; + source.read(buffer.get(), will_send); + size_t cb = write(buffer.get(), will_send); + size_sent += cb; + if (cb != will_send) { + break; + } + } + return size_sent; +} + #endif diff --git a/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/WiFiServer.h b/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/WiFiServer.h index 3dd02da7d..ef642762d 100644 --- a/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/WiFiServer.h +++ b/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/WiFiServer.h @@ -1,6 +1,6 @@ /* WiFiServer.h - Library for Arduino Wifi shield. - Copyright (c) 2011-2014 Arduino. All right reserved. + Copyright (c) 2011-2014 Arduino LLC. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public diff --git a/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/WiFiUdp.h b/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/WiFiUdp.h index a6bdc00da..f8d76cd05 100644 --- a/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/WiFiUdp.h +++ b/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/WiFiUdp.h @@ -1,6 +1,6 @@ /* WiFiUdp.h - Library for Arduino Wifi shield. - Copyright (c) 2011-2014 Arduino. All right reserved. + Copyright (c) 2011-2014 Arduino LLC. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public diff --git a/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/include/wl_definitions.h b/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/include/wl_definitions.h index a32ba45b2..45bee6764 100644 --- a/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/include/wl_definitions.h +++ b/hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/include/wl_definitions.h @@ -48,14 +48,14 @@ #define WL_MAX_ATTEMPT_CONNECTION 10 typedef enum { - WL_NO_SHIELD = 255, // for compatibility with WiFi Shield library - WL_IDLE_STATUS = 0, - WL_NO_SSID_AVAIL, - WL_SCAN_COMPLETED, - WL_CONNECTED, - WL_CONNECT_FAILED, - WL_CONNECTION_LOST, - WL_DISCONNECTED + WL_NO_SHIELD = 255, // for compatibility with WiFi Shield library + WL_IDLE_STATUS = 0, + WL_NO_SSID_AVAIL = 1, + WL_SCAN_COMPLETED = 2, + WL_CONNECTED = 3, + WL_CONNECT_FAILED = 4, + WL_CONNECTION_LOST = 5, + WL_DISCONNECTED = 6 } wl_status_t; /* Encryption modes */ diff --git a/hardware/esp8266com/esp8266/libraries/SPI/SPI.cpp b/hardware/esp8266com/esp8266/libraries/SPI/SPI.cpp index be4627740..7d52528ef 100644 --- a/hardware/esp8266com/esp8266/libraries/SPI/SPI.cpp +++ b/hardware/esp8266com/esp8266/libraries/SPI/SPI.cpp @@ -121,14 +121,14 @@ void SPIClass::setBitOrder(uint8_t bitOrder) { * @return */ static uint32_t ClkRegToFreq(spiClk_t * reg) { - return (F_CPU / ((reg->regPre + 1) * (reg->regN + 1))); + return (SPI_MAX_SPEED / ((reg->regPre + 1) * (reg->regN + 1))); } void SPIClass::setFrequency(uint32_t freq) { static uint32_t lastSetFrequency = 0; static uint32_t lastSetRegister = 0; - if(freq >= F_CPU) { + if(freq >= SPI_MAX_SPEED) { setClockDivider(0x80000000); return; } @@ -164,7 +164,7 @@ void SPIClass::setFrequency(uint32_t freq) { reg.regN = calN; while(calPreVari++ <= 1) { // test different variants for Pre (we calculate in int so we miss the decimals, testing is the easyest and fastest way) - calPre = (((F_CPU / (reg.regN + 1)) / freq) - 1) + calPreVari; + calPre = (((SPI_MAX_SPEED / (reg.regN + 1)) / freq) - 1) + calPreVari; if(calPre > 0x1FFF) { reg.regPre = 0x1FFF; // 8191 } else if(calPre <= 0) { @@ -308,6 +308,13 @@ void SPIClass::write32(uint32_t data, bool msb) { while(SPI1CMD & SPIBUSY) {} } +/** + * Note: + * data need to be aligned to 32Bit + * or you get an Fatal exception (9) + * @param data uint8_t * + * @param size uint32_t + */ void SPIClass::writeBytes(uint8_t * data, uint32_t size) { while(size) { if(size > 64) { @@ -340,6 +347,15 @@ void SPIClass::writeBytes_(uint8_t * data, uint8_t size) { while(SPI1CMD & SPIBUSY) {} } + +/** + * Note: + * data need to be aligned to 32Bit + * or you get an Fatal exception (9) + * @param data uint8_t * + * @param size uint8_t max for size is 64Byte + * @param repeat uint32_t + */ void SPIClass::writePattern(uint8_t * data, uint8_t size, uint32_t repeat) { if(size > 64) return; //max Hardware FIFO @@ -376,6 +392,14 @@ void SPIClass::writePattern_(uint8_t * data, uint8_t size, uint8_t repeat) { writeBytes(&buffer[0], bytes); } +/** + * Note: + * in and out need to be aligned to 32Bit + * or you get an Fatal exception (9) + * @param out uint8_t * + * @param in uint8_t * + * @param size uint32_t + */ void SPIClass::transferBytes(uint8_t * out, uint8_t * in, uint32_t size) { while(size) { if(size > 64) { diff --git a/hardware/esp8266com/esp8266/libraries/SPI/SPI.h b/hardware/esp8266com/esp8266/libraries/SPI/SPI.h index e67b5b0d5..68d2a3dc6 100644 --- a/hardware/esp8266com/esp8266/libraries/SPI/SPI.h +++ b/hardware/esp8266com/esp8266/libraries/SPI/SPI.h @@ -45,6 +45,8 @@ #define SPI_CLOCK_DIV64 0x04fc1001 //250 KHz #endif +#define SPI_MAX_SPEED (80000000L) + const uint8_t SPI_MODE0 = 0x00; ///< CPOL: 0 CPHA: 0 const uint8_t SPI_MODE1 = 0x01; ///< CPOL: 0 CPHA: 1 const uint8_t SPI_MODE2 = 0x10; ///< CPOL: 1 CPHA: 0 diff --git a/hardware/esp8266com/esp8266/platform.txt b/hardware/esp8266com/esp8266/platform.txt index cd09aff98..c2cfa053e 100644 --- a/hardware/esp8266com/esp8266/platform.txt +++ b/hardware/esp8266com/esp8266/platform.txt @@ -6,27 +6,27 @@ # https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5---3rd-party-Hardware-specification name=ESP8266 Modules -version=1.6.1 +version=1.6.4 -compiler.tools.path={runtime.ide.path}/hardware/tools/esp8266/ -compiler.path={compiler.tools.path}xtensa-lx106-elf/bin/ -compiler.sdk.path={compiler.tools.path}sdk/ +runtime.tools.xtensa-lx106-elf-gcc.path={runtime.platform.path}/tools/xtensa-lx106-elf +runtime.tools.esptool.path={runtime.platform.path}/tools +compiler.path={runtime.tools.xtensa-lx106-elf-gcc.path}/bin/ +compiler.sdk.path={runtime.platform.path}/tools/sdk/ compiler.cpreprocessor.flags=-D__ets__ -DICACHE_FLASH -U__STRICT_ANSI__ "-I{compiler.sdk.path}/include" compiler.c.cmd=xtensa-lx106-elf-gcc -compiler.c.flags=-c -Os -Wpointer-arith -Wno-implicit-function-declaration -Wl,-EL -fno-inline-functions -nostdlib -mlongcalls -mtext-section-literals -MMD -std=c99 +compiler.c.flags=-c -Os -Wpointer-arith -Wno-implicit-function-declaration -Wl,-EL -fno-inline-functions -nostdlib -mlongcalls -mtext-section-literals -falign-functions=4 -MMD -std=c99 compiler.S.cmd=xtensa-lx106-elf-gcc compiler.S.flags=-c -g -x assembler-with-cpp -MMD -compiler.c.elf.ldscript=eagle.app.v6.ld -compiler.c.elf.flags=-nostdlib -Wl,--no-check-sections -u call_user_start -Wl,-static "-L{compiler.sdk.path}/lib" "-L{compiler.sdk.path}/ld" "-T{compiler.c.elf.ldscript}" +compiler.c.elf.flags=-nostdlib -Wl,--no-check-sections -u call_user_start -Wl,-static "-L{compiler.sdk.path}/lib" "-L{compiler.sdk.path}/ld" "-T{build.flash_ld}" compiler.c.elf.cmd=xtensa-lx106-elf-gcc compiler.c.elf.libs=-lm -lgcc -lhal -lphy -lnet80211 -llwip -lwpa -lmain -lpp -lsmartconfig compiler.cpp.cmd=xtensa-lx106-elf-g++ -compiler.cpp.flags=-c -Os -mlongcalls -mtext-section-literals -fno-exceptions -fno-rtti -std=c++11 -MMD +compiler.cpp.flags=-c -Os -mlongcalls -mtext-section-literals -fno-exceptions -fno-rtti -falign-functions=4 -std=c++11 -MMD compiler.as.cmd=xtensa-lx106-elf-as @@ -34,12 +34,12 @@ compiler.ar.cmd=xtensa-lx106-elf-ar compiler.ar.flags=cru compiler.elf2hex.cmd=esptool - compiler.elf2hex.flags= compiler.size.cmd=xtensa-lx106-elf-size compiler.esptool.cmd=esptool +compiler.esptool.cmd.windows=esptool.exe # This can be overriden in boards.txt build.extra_flags=-DESP8266 @@ -74,7 +74,7 @@ recipe.objcopy.eep.pattern= ## Create hex #recipe.objcopy.hex.pattern="{compiler.path}{compiler.elf2hex.cmd}" {compiler.elf2hex.flags} {compiler.elf2hex.extra_flags} "{build.path}/{build.project_name}.elf" "{build.path}/{build.project_name}.hex" -recipe.objcopy.hex.pattern="{compiler.tools.path}{compiler.esptool.cmd}" -eo "{build.path}/{build.project_name}.elf" -bo "{build.path}/{build.project_name}_00000.bin" -bm {build.flash_mode} -bf {build.flash_freq} -bz {build.flash_size} -bs .text -bs .data -bs .rodata -bc -ec -eo "{build.path}/{build.project_name}.elf" -es .irom0.text "{build.path}/{build.project_name}_10000.bin" -ec +recipe.objcopy.hex.pattern="{runtime.tools.esptool.path}/{compiler.esptool.cmd}" -eo "{build.path}/{build.project_name}.elf" -bo "{build.path}/{build.project_name}_00000.bin" -bm {build.flash_mode} -bf {build.flash_freq} -bz {build.flash_size} -bs .text -bs .data -bs .rodata -bc -ec -eo "{build.path}/{build.project_name}.elf" -es .irom0.text "{build.path}/{build.project_name}_10000.bin" -ec ## Compute size recipe.size.pattern="{compiler.path}{compiler.size.cmd}" -A "{build.path}/{build.project_name}.elf" @@ -86,7 +86,7 @@ recipe.size.regex=^(?:\.text|\.data|\.rodata|\.irom0\.text|)\s+([0-9]+).* tools.esptool.cmd=esptool tools.esptool.cmd.windows=esptool.exe -tools.esptool.path={runtime.ide.path}/hardware/tools/esp8266 +tools.esptool.path={runtime.platform.path}/tools tools.esptool.upload.protocol=esp tools.esptool.upload.params.verbose=-vv diff --git a/hardware/tools/esp8266/sdk/License b/hardware/esp8266com/esp8266/tools/sdk/License similarity index 99% rename from hardware/tools/esp8266/sdk/License rename to hardware/esp8266com/esp8266/tools/sdk/License index dcd0fcc3c..38adccb1e 100644 --- a/hardware/tools/esp8266/sdk/License +++ b/hardware/esp8266com/esp8266/tools/sdk/License @@ -1,68 +1,68 @@ -ESPRESSIF GENERAL PUBLIC LICENSE - -PREAMBLE - -The Espressif General Public License is a free, copyleft license for software and other kinds of works. -The Espressif General Public License is intended to guarantee your freedom to share and change all versions of a program released by ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD, to make sure it remains free software for all its users. We use the Espressif General Public License for all of our open-source software. -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 them 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 prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. 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. -Developers that use the Espressif GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. -For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. - -TERMS AND CONDITIONS - -0. Definitions. -¡°This License¡± refers to the Espressif Public License. - -¡°The Program¡± refers to any copyrightable work licensed under this License. Each licensee is addressed as ¡°you¡±. ¡°Licensees¡± and ¡°recipients¡± may be individuals or organizations. -To ¡°modify¡± a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a ¡°modified version¡± of the earlier work or a work ¡°based on¡± the earlier work. -A ¡°covered work¡± means either the unmodified Program or a work based on the Program. -To ¡°propagate¡± a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. -To ¡°convey¡± a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. -1. Basic Permissions. -All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. -You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. -Conveying under any other circumstances is permitted solely under the conditions stated below. - -2. Protecting Users' Legal Rights From Anti-Circumvention Law. -No covered work shall be deemed part of an effective technological measure under any applicable law prohibiting or restricting circumvention of such measures. -When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. - -3. Conveying Verbatim Copies. -You may convey 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; keep intact all notices stating that this License applies to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. -You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. - -4. Conveying Modified Source Versions. -You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 3, provided that you also meet all of these conditions: -a) The work must carry prominent notices stating that you modified it, and giving a relevant date. -b) The work must carry prominent notices stating that it is released under this License. This requirement modifies the requirement in section 3 to ¡°keep intact all notices¡±. -c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. - -5. Termination. -You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License. -However, if you cease all violation of this License, then your license is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license. -Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 7. - -6. Acceptance Not Required for Having Copies. -You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. - -7. Automatic Licensing of Downstream Recipients. -Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. - -8. No Surrender of Others' Freedom. -If 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 convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. -9. Revised Versions of this License. -ESPRESSIF SYSTEMS (SHANGHAI) PTE LED may publish revised and/or new versions of the ESPRESSIF 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 that a certain numbered version of the Espressif General Public License ¡°or any later version¡± applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD. If the Program does not specify a version number of the Espressif General Public License, you may choose any version ever published. - -10. Disclaimer of Warranty. -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. - -11. Limitation of Liability. -IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 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. - - -12. Interpretation of Sections 10 and 11. -If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. - -END OF TERMS AND CONDITIONS +ESPRESSIF GENERAL PUBLIC LICENSE + +PREAMBLE + +The Espressif General Public License is a free, copyleft license for software and other kinds of works. +The Espressif General Public License is intended to guarantee your freedom to share and change all versions of a program released by ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD, to make sure it remains free software for all its users. We use the Espressif General Public License for all of our open-source software. +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 them 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 prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. 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. +Developers that use the Espressif GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. +For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. + +TERMS AND CONDITIONS + +0. Definitions. +¡°This License¡± refers to the Espressif Public License. + +¡°The Program¡± refers to any copyrightable work licensed under this License. Each licensee is addressed as ¡°you¡±. ¡°Licensees¡± and ¡°recipients¡± may be individuals or organizations. +To ¡°modify¡± a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a ¡°modified version¡± of the earlier work or a work ¡°based on¡± the earlier work. +A ¡°covered work¡± means either the unmodified Program or a work based on the Program. +To ¡°propagate¡± a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. +To ¡°convey¡± a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. +1. Basic Permissions. +All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. +You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. +Conveying under any other circumstances is permitted solely under the conditions stated below. + +2. Protecting Users' Legal Rights From Anti-Circumvention Law. +No covered work shall be deemed part of an effective technological measure under any applicable law prohibiting or restricting circumvention of such measures. +When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. + +3. Conveying Verbatim Copies. +You may convey 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; keep intact all notices stating that this License applies to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. +You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. + +4. Conveying Modified Source Versions. +You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 3, provided that you also meet all of these conditions: +a) The work must carry prominent notices stating that you modified it, and giving a relevant date. +b) The work must carry prominent notices stating that it is released under this License. This requirement modifies the requirement in section 3 to ¡°keep intact all notices¡±. +c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. + +5. Termination. +You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License. +However, if you cease all violation of this License, then your license is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license. +Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 7. + +6. Acceptance Not Required for Having Copies. +You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. + +7. Automatic Licensing of Downstream Recipients. +Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. + +8. No Surrender of Others' Freedom. +If 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 convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. +9. Revised Versions of this License. +ESPRESSIF SYSTEMS (SHANGHAI) PTE LED may publish revised and/or new versions of the ESPRESSIF 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 that a certain numbered version of the Espressif General Public License ¡°or any later version¡± applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD. If the Program does not specify a version number of the Espressif General Public License, you may choose any version ever published. + +10. Disclaimer of Warranty. +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. + +11. Limitation of Liability. +IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 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. + + +12. Interpretation of Sections 10 and 11. +If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. + +END OF TERMS AND CONDITIONS diff --git a/hardware/tools/esp8266/sdk/changelog.txt b/hardware/esp8266com/esp8266/tools/sdk/changelog.txt similarity index 97% rename from hardware/tools/esp8266/sdk/changelog.txt rename to hardware/esp8266com/esp8266/tools/sdk/changelog.txt index 68a53e296..86bb16cee 100644 --- a/hardware/tools/esp8266/sdk/changelog.txt +++ b/hardware/esp8266com/esp8266/tools/sdk/changelog.txt @@ -1,274 +1,274 @@ -esp_iot_sdk_v1.0.1_15_05_04_p1 -------------------------------------------- -Here is a patch for station+softAP issue that users may have, based on SDK_v1.0.1, -solved problem that connect to ESP8266 softAP may fail in station+softAP mode. - -Sorry for the inconvenience. - -esp_iot_sdk_v1.0.1_15_04_24 Release Note -------------------------------------------- - -Resolved Issues(Bugs below are eligible for Bug Bounty Program): -1. SSL connection may fail if SSL packet size larger than 2kBytes [PeteW ] -2. UDP remote IP to be 0.0.0.0 may cause reset [Jerry S] -3. Optimize wifi_get_ip_info to fix loss of wireless connectivity problem -4. Air-Kiss restart [Orgmar] - -Optimization: -1. Optimized IOT_Espressif_EspTouch.APK (apply for access from Espressif) for improved compatibility. [???] -2. TCP server can not open again immediately with the same port [624908539] -3. Update UART driver for parity bit value may be incorrect [1062583993] -4. Add define of “ICACHE_RODATA_ATTR” for Symbol 'ICACHE_RODATA_ATTR' could not be resolved. [???] -5. Add API wifi_softap_dhcps_set_offer_option to enable/disable ESP8266 softAP DHCP server default gateway. [xyz769] -6. AT register_uart_rx_intr may enter callback twice. [???] -7.optimize document that WPA password length range : 8 ~ 64 bytes [785057041] -8. ESP8266 softAP DHCP server record 8 DHCP client's IP at most [ygjeon] -9. To set static IP (wifi_set_ip_info) has to disable DHCP first(wifi_softap_dhcps_stop or wifi_station_dhcpc_stop) -10.Add example of wifi_softap_set_dhcps_lease -11. smartconfig_start can only be called in ESP8266 station mode - -Added APIs: -1. Wi-Fi related APIs: -wifi_station_set_reconnect_policy: enable/disable reconnect when ESP8266 disconnect from router,default to be enable reconnect. -wifi_set_event_handler_cb: set event handler of ESP8266 softAP or station status change. -wifi_softap_dhcps_set_offer_option: enable/disable get router information from ESP8266 softAP, default to be enable. -2. SNTP APIs: -sntp_get_current_timestamp: get current timestamp from Jan 01, 1970, 00:00 (GMT) -sntp_get_real_time: char,get real time (GTM + 8 time zone) -sntp_init: initialize SNTP -sntp_stop: stop SNTP -sntp_setserver: set SNTP server by IP -sntp_getserver: get SNTP server IP -sntp_setservername: set SNTP server by domain name -sntp_getservername: get domain name of SNTP server set by sntp_setservername -3. MDNS APIs: -espconn_mdns_init: initialize mDNS -espconn_mdns_close: close mDNS -espconn_mdns_server_register: register mDNS server -espconn_mdns_server_unregister: unregister mDNS server -espconn_mdns_get_servername: get mDNS server name -espconn_mdns_set_servername: set mDNS server name -espconn_mdns_set_hostname: get mDNS host name -espconn_mdns_get_hostname: set mDNS host name -espconn_mdns_disable: disable mDNS -espconn_mdns_enable: endisable mDNS - -AT_v0.23 Release Note: -Optimized: -1.AT+CWJAP add parameter "bssid", for several APs may have the same SSID - -New AT commands: -1. AT+CIPSENDBUF: write data into TCP-send-buffer; non-blocking. Background task automatically handles transmission. Has much higher throughput. -2. AT+CIPBUFRESET: resets segment count in TCP-send-buffer -3. AT+CIPBUFSTATUS: checks status of TCP-send-buffer -4. AT+CIPCHECKSEGID: checks if a specific segment in TCP-send-buffer has sent successfully - - - -esp_iot_sdk_v1.0.1_b2_15_04_10 release note -------------------------------------------- - -Fix bugs: -1.Call espconn_sent to send UDP packet in user_init cause reset.[BBP#2 reporter (????)] -2.UART & FlowControl issue: send data to FIFO without CTS flag will cause WDT [BBP#11 reporter (pvxx)] -3.SSL issue,add an API (espconn_secure_set_size) to set SSL buffer size [BBP#29 reporter (PeteW)] -4.UDP broadcast issue in WEP - -Optimize: -1.Add more details about measure ADC & VDD3P3 in appendix of document“2C-SDK-Espressif IoT SDK Programming Guide”[BBP#15 reporter (DarkByte)] -2.Can not do any WiFi related operation if WiFi mode is in NULL_MODE [BBP#23 reporter (hao.wang)] -3.start_ip and end_ip won't change through API wifi_softap_set_dhcps_lease [BBP#37 reporter (glb)] -4.AT get into busy state [BBP#35 reporter (tommy_hk)] -5.ssid + password length limitation when using AirKiss [BBP#45 reporter (zhchbin)] - -Add APIs: -1.espconn_secure_set_size:set buffer size for SSL packet -2.espconn_secure_get_size:get SSL buffer size -3.at_register_uart_rx_intr:set UART0 to be used by user or AT commands - -Add AT command: -1.AT+SLEEP: set ESP8266 sleep mode - -esp_iot_sdk_v1.0.1_b1_15_04_02 Release note -------------------------------------------- - -Fix bugs: -1. Connect to ESP8266 softAP fail after SmartConfig; -2. SmartConfig loses one bit of SSID - -Optimize: -1. espconn_set_opt: set configuration of TCP connection,add parameter for TCP keep-alive - -Add APIs: -1. espconn_clear_opt: clear configuration of TCP connection -2. espconn_set_keepalive: set configuration of TCP keep-alive to detect if TCP connection broke -3. espconn_get_keepalive: get configuration of TCP keep-alive - -AT_v0.23_b1 release note -Note: AT added some functions so flash size need to be 1024KB or more than that. - -Fix bug: -1. Always "busy" if TCP connection abnormally broke during AT+CIPSEND - -Optimize: -1. Add UDP transparent transmission -2. Optimize the initial value of AT+CWDHCP? -3. Add TCP keep-alive function in AT+CIPSTART - -Add AT command: -1. Add AT+CIPSENDEX which support quit from sending mode by "\0" (so an useful "\0" need to be "\\0") - -esp_iot_sdk_v1.0.0_15_03_20 Release Note ----------------------------------------- - -Optimize: -1. Optimize smartconfig to version v1.0; Please don't call any other APIs during SmartConfig. -2. Optimize AT to version 0.22.0.0; -3. Optimize the protection of system parameters, and add error-check about it; -4. Optimize beacon delay of ESP8266 softAP; -5. Optimize boot to version 1.3(b3); - - Add API system_restart_enhance: for factory test, support to load and run program in any specific address; - - Add APIs to get boot version and start address of current user bin; - - Fix compatibility problem of dual flash; -6. Optimize sniffer, structure sniffer_buf changed, please refer to document; -7. Optimize espconn; -8. Optimize pwm; -9. Other optimize to make the software more reliable; - -Add APIs: -1. system_update_cpu_freq: change CPU frequency; -2. wifi_promiscuous_set_mac: set a mac address filter during sniffer; -3. wifi_set_broadcast_if : set which interface will UDP broadcast send from; - -Fix bugs: -1. Interrupt during flash erasing will cause wdt reset; -2. Read/write rtc memory; -3. If router disconnect to ESP8266, ESP8266 won't reconnect; -4. Connect to router which hid its SSID - -AT_v0.22 release note - -Fix bug: -1. Wrong return value of AT+CIPSTATUS; -2. wdt rest after "0,CONNECT FAIL"; - -Add AT commands: -1. Change AT commands of which configuration will store into flash to two kinds: - XXX_CUR: current, only set configuration won't save it into Flash; - XXX_DEF: default, set configuration and save it to Flash -2. Add SmartConfig in AT: - AT+CWSTARTSMART/AT+CWSTOPSMART: start / stop SmartConfig - Notice: please refer to the document, call "AT+CWSTOPSMART" to stop SmartConfig first since "AT+CWSTARTSMART", then call other AT commands. Don't call any other AT commands during SmartConfig. -2. AT+SAVETRANSLINK: save transparent transmission link to Flash; - Note:AT+CIPMODE=1 set to enter transparent transmission mode, won't save to Flash. - - -Add AT APIs -1. at_customLinkMax: set the max link that allowed, most can be 10; if you want to set it, please set it before at_init; if you didn't set it, the max link allowed is 5 by default. -2. at_enter_special_state/ at_leave_special_state:Enter/leave AT processing state. In processing state, AT core will return "busy" for any further AT commands. -3. at_set_custom_info:set custom version information of AT which can be got by AT+GMR; -4. at_get_version:get version information of AT lib . - -Optimize -1. Add UDP remote ip and remote port is allowed to be parameters of "AT+CIPSEND" -2. Move "AT+CIUPDATE" from lib to AT "demo\esp_iot_sdk\examples\at", AT demo shows how to upgrade AT firmware from a local server. Notice that AT upgrade the bin files name have to be "user1.bin" and "user2.bin". -3. Optimize "AT+CIPSTA", add gateway and netmask as parameters -4. Optimize transparent transmission. - -esp_iot_sdk_v0.9.5_15_01_22 Release Note ----------------------------------------- - -AT becomes a lib attached to esp_iot_sdk, programming guide in "document" shows APIs for user to define their own AT commands, AT bin files are in \esp_iot_sdk\bin\at - -Fix bugs: -1. Incorrect status got by API : wifi_station_get_connect_status; -2. Sniffer can not quit without restart; -3. wifi_station_ap_change always return true; -4. TCP connection issues - -Add APIs: -1. system_deep_sleep_set_option: set what the chip will do when deep-sleep wake up; -2. wifi_status_led_uninstall; -3. wifi_station_ap_get_info: get information of AP that ESP8266 station connected. -4. wifi_station_dhcpc_status & wifi_softap_dhcps_status : get DHCP status -5. smart config APIs, more details in documents. -6. add beacon_interval parameter in struct softap_config -7. espconn_recv_hold and espconn_recv_unhold to block TCP receiving data and unblock it. -8. AT APIs to let user define their own AT, more details in documents. - -Optimize: -1. light sleep, modem sleep, deep sleep -2. compile method: ./gen_misc.sh, then follow the tips and steps. -3. when no buffer for os_malloc, return NULL instead of malloc assert. -4. users can enable #define USE_OPTIMIZE_PRINTF in user_config.h to remove strings of os_printf from ram to irom -5. faster the re-connection of ESP8266 station to router after deep-sleep. -6. update to boot v1.2 to support new format user.bin; -7. update ARP -8. update SSL -9. revised system_deep_sleep,system_deep_sleep(0),set no wake up timer,connect a GPIO to pin RST, the chip will wake up by a falling-edge on pin RST - -esp_iot_sdk_v0.9.4_14_12_19 Release Note ----------------------------------------- - -1. Update sniffer to support capture HT20/HT40 packet; -2. Add APIs to set and get sleep type; -3. Add APIs to get version info of sdk, delete version.h; -4. RAW in LWIP is open source now, add API of function ping; -5. Update spi driver; -6. Optimize APIs related to espconn; -7. Fix some bugs to make the software more reliable; - -Known Issue: -1. exception of small probability occured while recving multi-client data in softap -2. restart of small probability occured while tcp client reconnecting - -So sorry that we have some known issues here, we will solve it ASAP. - -esp_iot_sdk_v0.9.3_14_11_21 Release Note ----------------------------------------- - -1. Add license documentation of ESPRESSIF SDK -2. Add APIs to read and write RTC memory, and APIs to get RTC time. -3. Add APIs to swap UART0 -4. Add API to read ADC, delete adc.c. -5. Add API to read spi flash id -6. Revise struct station_config, add bssid parameters to distinguish different AP with same ssid ; - Note: if station_config.bssid_set == 1 , station_config.bssid has to be set, or connection will fail. So in general, station_config.bssid_set need to be 0. -7. Revise struct scan_config, add scan_config.show_hidden to set whether scan APs which ssid is hidden or not; not scan, set scan_config.show_hidden to be 0. - Add bss_info.is_hidden in struct bss_info to show if this APTs ssid is hidden. -8. Revise struct softap_config, add softap_config.ssid_len. If softap_config.ssid_len == 0, check ssid till find a termination characters; otherwise it depends on softap_config.ssid_len. -9. Revise API "wifi_softap_set_config" to take effect immediately, needs not restart to make the configuration enable any more. -10. Add APIs to set and get physical layer mode(802.11b/g/n) -11. Add APIs to enable and disable DHCP server of ESP8266 softAP -12. Add APIs to enable and disable DHCP client of ESP8266 station -13. Add API to set range of ip address that get from DHCP server -14. Add APIs to set and get how many TCP connections allowed at max. -15. Add APIs to set and get how many TCP clients allowed at max to a TCP server. -16. Revise "wifi_set_ip_info" and "wifi_set_macaddr" to take effect immediately. -17. Fix some bugs to make the software more reliable. - -ESP8266EX: Fix A Potential Error For UART RX in esp_iot_sdk_v0.9.2_14_10_24 ---------------------------------------------------------------------------- - -The previously released SDK for ESP8266EX inadvertently introduced a bug that may cause a little packet loss when transferring packet by Uart RX. -So for now,I will release the patch for this bug.Please download the patch from the attachment,and refer to the following steps: -Following Commands: -1. REPLACE LIBPHY.A IN SDK/LIB -2. ADD LIBPP.A TO SDK/LIB -3. MODIFY SDK/APP/MAKEFILE -4. ADD "-lpp \" AS BELOW --lgcc --lhal --lpp --lphy --lnet80211 --llwip --lwpa --lmain --lssc --lssl - -esp_iot_sdk_v0.9.2_14_10_24 Release Note ----------------------------------------- - -Initial version for public, can be compiled on both windows and lubuntu. +esp_iot_sdk_v1.0.1_15_05_04_p1 +------------------------------------------- +Here is a patch for station+softAP issue that users may have, based on SDK_v1.0.1, +solved problem that connect to ESP8266 softAP may fail in station+softAP mode. + +Sorry for the inconvenience. + +esp_iot_sdk_v1.0.1_15_04_24 Release Note +------------------------------------------- + +Resolved Issues(Bugs below are eligible for Bug Bounty Program): +1. SSL connection may fail if SSL packet size larger than 2kBytes [PeteW ] +2. UDP remote IP to be 0.0.0.0 may cause reset [Jerry S] +3. Optimize wifi_get_ip_info to fix loss of wireless connectivity problem +4. Air-Kiss restart [Orgmar] + +Optimization: +1. Optimized IOT_Espressif_EspTouch.APK (apply for access from Espressif) for improved compatibility. [???] +2. TCP server can not open again immediately with the same port [624908539] +3. Update UART driver for parity bit value may be incorrect [1062583993] +4. Add define of “ICACHE_RODATA_ATTR” for Symbol 'ICACHE_RODATA_ATTR' could not be resolved. [???] +5. Add API wifi_softap_dhcps_set_offer_option to enable/disable ESP8266 softAP DHCP server default gateway. [xyz769] +6. AT register_uart_rx_intr may enter callback twice. [???] +7.optimize document that WPA password length range : 8 ~ 64 bytes [785057041] +8. ESP8266 softAP DHCP server record 8 DHCP client's IP at most [ygjeon] +9. To set static IP (wifi_set_ip_info) has to disable DHCP first(wifi_softap_dhcps_stop or wifi_station_dhcpc_stop) +10.Add example of wifi_softap_set_dhcps_lease +11. smartconfig_start can only be called in ESP8266 station mode + +Added APIs: +1. Wi-Fi related APIs: +wifi_station_set_reconnect_policy: enable/disable reconnect when ESP8266 disconnect from router,default to be enable reconnect. +wifi_set_event_handler_cb: set event handler of ESP8266 softAP or station status change. +wifi_softap_dhcps_set_offer_option: enable/disable get router information from ESP8266 softAP, default to be enable. +2. SNTP APIs: +sntp_get_current_timestamp: get current timestamp from Jan 01, 1970, 00:00 (GMT) +sntp_get_real_time: char,get real time (GTM + 8 time zone) +sntp_init: initialize SNTP +sntp_stop: stop SNTP +sntp_setserver: set SNTP server by IP +sntp_getserver: get SNTP server IP +sntp_setservername: set SNTP server by domain name +sntp_getservername: get domain name of SNTP server set by sntp_setservername +3. MDNS APIs: +espconn_mdns_init: initialize mDNS +espconn_mdns_close: close mDNS +espconn_mdns_server_register: register mDNS server +espconn_mdns_server_unregister: unregister mDNS server +espconn_mdns_get_servername: get mDNS server name +espconn_mdns_set_servername: set mDNS server name +espconn_mdns_set_hostname: get mDNS host name +espconn_mdns_get_hostname: set mDNS host name +espconn_mdns_disable: disable mDNS +espconn_mdns_enable: endisable mDNS + +AT_v0.23 Release Note: +Optimized: +1.AT+CWJAP add parameter "bssid", for several APs may have the same SSID + +New AT commands: +1. AT+CIPSENDBUF: write data into TCP-send-buffer; non-blocking. Background task automatically handles transmission. Has much higher throughput. +2. AT+CIPBUFRESET: resets segment count in TCP-send-buffer +3. AT+CIPBUFSTATUS: checks status of TCP-send-buffer +4. AT+CIPCHECKSEGID: checks if a specific segment in TCP-send-buffer has sent successfully + + + +esp_iot_sdk_v1.0.1_b2_15_04_10 release note +------------------------------------------- + +Fix bugs: +1.Call espconn_sent to send UDP packet in user_init cause reset.[BBP#2 reporter (????)] +2.UART & FlowControl issue: send data to FIFO without CTS flag will cause WDT [BBP#11 reporter (pvxx)] +3.SSL issue,add an API (espconn_secure_set_size) to set SSL buffer size [BBP#29 reporter (PeteW)] +4.UDP broadcast issue in WEP + +Optimize: +1.Add more details about measure ADC & VDD3P3 in appendix of document“2C-SDK-Espressif IoT SDK Programming Guide”[BBP#15 reporter (DarkByte)] +2.Can not do any WiFi related operation if WiFi mode is in NULL_MODE [BBP#23 reporter (hao.wang)] +3.start_ip and end_ip won't change through API wifi_softap_set_dhcps_lease [BBP#37 reporter (glb)] +4.AT get into busy state [BBP#35 reporter (tommy_hk)] +5.ssid + password length limitation when using AirKiss [BBP#45 reporter (zhchbin)] + +Add APIs: +1.espconn_secure_set_size:set buffer size for SSL packet +2.espconn_secure_get_size:get SSL buffer size +3.at_register_uart_rx_intr:set UART0 to be used by user or AT commands + +Add AT command: +1.AT+SLEEP: set ESP8266 sleep mode + +esp_iot_sdk_v1.0.1_b1_15_04_02 Release note +------------------------------------------- + +Fix bugs: +1. Connect to ESP8266 softAP fail after SmartConfig; +2. SmartConfig loses one bit of SSID + +Optimize: +1. espconn_set_opt: set configuration of TCP connection,add parameter for TCP keep-alive + +Add APIs: +1. espconn_clear_opt: clear configuration of TCP connection +2. espconn_set_keepalive: set configuration of TCP keep-alive to detect if TCP connection broke +3. espconn_get_keepalive: get configuration of TCP keep-alive + +AT_v0.23_b1 release note +Note: AT added some functions so flash size need to be 1024KB or more than that. + +Fix bug: +1. Always "busy" if TCP connection abnormally broke during AT+CIPSEND + +Optimize: +1. Add UDP transparent transmission +2. Optimize the initial value of AT+CWDHCP? +3. Add TCP keep-alive function in AT+CIPSTART + +Add AT command: +1. Add AT+CIPSENDEX which support quit from sending mode by "\0" (so an useful "\0" need to be "\\0") + +esp_iot_sdk_v1.0.0_15_03_20 Release Note +---------------------------------------- + +Optimize: +1. Optimize smartconfig to version v1.0; Please don't call any other APIs during SmartConfig. +2. Optimize AT to version 0.22.0.0; +3. Optimize the protection of system parameters, and add error-check about it; +4. Optimize beacon delay of ESP8266 softAP; +5. Optimize boot to version 1.3(b3); + - Add API system_restart_enhance: for factory test, support to load and run program in any specific address; + - Add APIs to get boot version and start address of current user bin; + - Fix compatibility problem of dual flash; +6. Optimize sniffer, structure sniffer_buf changed, please refer to document; +7. Optimize espconn; +8. Optimize pwm; +9. Other optimize to make the software more reliable; + +Add APIs: +1. system_update_cpu_freq: change CPU frequency; +2. wifi_promiscuous_set_mac: set a mac address filter during sniffer; +3. wifi_set_broadcast_if : set which interface will UDP broadcast send from; + +Fix bugs: +1. Interrupt during flash erasing will cause wdt reset; +2. Read/write rtc memory; +3. If router disconnect to ESP8266, ESP8266 won't reconnect; +4. Connect to router which hid its SSID + +AT_v0.22 release note + +Fix bug: +1. Wrong return value of AT+CIPSTATUS; +2. wdt rest after "0,CONNECT FAIL"; + +Add AT commands: +1. Change AT commands of which configuration will store into flash to two kinds: + XXX_CUR: current, only set configuration won't save it into Flash; + XXX_DEF: default, set configuration and save it to Flash +2. Add SmartConfig in AT: + AT+CWSTARTSMART/AT+CWSTOPSMART: start / stop SmartConfig + Notice: please refer to the document, call "AT+CWSTOPSMART" to stop SmartConfig first since "AT+CWSTARTSMART", then call other AT commands. Don't call any other AT commands during SmartConfig. +2. AT+SAVETRANSLINK: save transparent transmission link to Flash; + Note:AT+CIPMODE=1 set to enter transparent transmission mode, won't save to Flash. + + +Add AT APIs +1. at_customLinkMax: set the max link that allowed, most can be 10; if you want to set it, please set it before at_init; if you didn't set it, the max link allowed is 5 by default. +2. at_enter_special_state/ at_leave_special_state:Enter/leave AT processing state. In processing state, AT core will return "busy" for any further AT commands. +3. at_set_custom_info:set custom version information of AT which can be got by AT+GMR; +4. at_get_version:get version information of AT lib . + +Optimize +1. Add UDP remote ip and remote port is allowed to be parameters of "AT+CIPSEND" +2. Move "AT+CIUPDATE" from lib to AT "demo\esp_iot_sdk\examples\at", AT demo shows how to upgrade AT firmware from a local server. Notice that AT upgrade the bin files name have to be "user1.bin" and "user2.bin". +3. Optimize "AT+CIPSTA", add gateway and netmask as parameters +4. Optimize transparent transmission. + +esp_iot_sdk_v0.9.5_15_01_22 Release Note +---------------------------------------- + +AT becomes a lib attached to esp_iot_sdk, programming guide in "document" shows APIs for user to define their own AT commands, AT bin files are in \esp_iot_sdk\bin\at + +Fix bugs: +1. Incorrect status got by API : wifi_station_get_connect_status; +2. Sniffer can not quit without restart; +3. wifi_station_ap_change always return true; +4. TCP connection issues + +Add APIs: +1. system_deep_sleep_set_option: set what the chip will do when deep-sleep wake up; +2. wifi_status_led_uninstall; +3. wifi_station_ap_get_info: get information of AP that ESP8266 station connected. +4. wifi_station_dhcpc_status & wifi_softap_dhcps_status : get DHCP status +5. smart config APIs, more details in documents. +6. add beacon_interval parameter in struct softap_config +7. espconn_recv_hold and espconn_recv_unhold to block TCP receiving data and unblock it. +8. AT APIs to let user define their own AT, more details in documents. + +Optimize: +1. light sleep, modem sleep, deep sleep +2. compile method: ./gen_misc.sh, then follow the tips and steps. +3. when no buffer for os_malloc, return NULL instead of malloc assert. +4. users can enable #define USE_OPTIMIZE_PRINTF in user_config.h to remove strings of os_printf from ram to irom +5. faster the re-connection of ESP8266 station to router after deep-sleep. +6. update to boot v1.2 to support new format user.bin; +7. update ARP +8. update SSL +9. revised system_deep_sleep,system_deep_sleep(0),set no wake up timer,connect a GPIO to pin RST, the chip will wake up by a falling-edge on pin RST + +esp_iot_sdk_v0.9.4_14_12_19 Release Note +---------------------------------------- + +1. Update sniffer to support capture HT20/HT40 packet; +2. Add APIs to set and get sleep type; +3. Add APIs to get version info of sdk, delete version.h; +4. RAW in LWIP is open source now, add API of function ping; +5. Update spi driver; +6. Optimize APIs related to espconn; +7. Fix some bugs to make the software more reliable; + +Known Issue: +1. exception of small probability occured while recving multi-client data in softap +2. restart of small probability occured while tcp client reconnecting + +So sorry that we have some known issues here, we will solve it ASAP. + +esp_iot_sdk_v0.9.3_14_11_21 Release Note +---------------------------------------- + +1. Add license documentation of ESPRESSIF SDK +2. Add APIs to read and write RTC memory, and APIs to get RTC time. +3. Add APIs to swap UART0 +4. Add API to read ADC, delete adc.c. +5. Add API to read spi flash id +6. Revise struct station_config, add bssid parameters to distinguish different AP with same ssid ; + Note: if station_config.bssid_set == 1 , station_config.bssid has to be set, or connection will fail. So in general, station_config.bssid_set need to be 0. +7. Revise struct scan_config, add scan_config.show_hidden to set whether scan APs which ssid is hidden or not; not scan, set scan_config.show_hidden to be 0. + Add bss_info.is_hidden in struct bss_info to show if this APTs ssid is hidden. +8. Revise struct softap_config, add softap_config.ssid_len. If softap_config.ssid_len == 0, check ssid till find a termination characters; otherwise it depends on softap_config.ssid_len. +9. Revise API "wifi_softap_set_config" to take effect immediately, needs not restart to make the configuration enable any more. +10. Add APIs to set and get physical layer mode(802.11b/g/n) +11. Add APIs to enable and disable DHCP server of ESP8266 softAP +12. Add APIs to enable and disable DHCP client of ESP8266 station +13. Add API to set range of ip address that get from DHCP server +14. Add APIs to set and get how many TCP connections allowed at max. +15. Add APIs to set and get how many TCP clients allowed at max to a TCP server. +16. Revise "wifi_set_ip_info" and "wifi_set_macaddr" to take effect immediately. +17. Fix some bugs to make the software more reliable. + +ESP8266EX: Fix A Potential Error For UART RX in esp_iot_sdk_v0.9.2_14_10_24 +--------------------------------------------------------------------------- + +The previously released SDK for ESP8266EX inadvertently introduced a bug that may cause a little packet loss when transferring packet by Uart RX. +So for now,I will release the patch for this bug.Please download the patch from the attachment,and refer to the following steps: +Following Commands: +1. REPLACE LIBPHY.A IN SDK/LIB +2. ADD LIBPP.A TO SDK/LIB +3. MODIFY SDK/APP/MAKEFILE +4. ADD "-lpp \" AS BELOW +-lgcc +-lhal +-lpp +-lphy +-lnet80211 +-llwip +-lwpa +-lmain +-lssc +-lssl + +esp_iot_sdk_v0.9.2_14_10_24 Release Note +---------------------------------------- + +Initial version for public, can be compiled on both windows and lubuntu. diff --git a/hardware/tools/esp8266/sdk/include/c_types.h b/hardware/esp8266com/esp8266/tools/sdk/include/c_types.h similarity index 100% rename from hardware/tools/esp8266/sdk/include/c_types.h rename to hardware/esp8266com/esp8266/tools/sdk/include/c_types.h diff --git a/hardware/tools/esp8266/sdk/include/eagle_soc.h b/hardware/esp8266com/esp8266/tools/sdk/include/eagle_soc.h similarity index 100% rename from hardware/tools/esp8266/sdk/include/eagle_soc.h rename to hardware/esp8266com/esp8266/tools/sdk/include/eagle_soc.h diff --git a/hardware/tools/esp8266/sdk/include/espconn.h b/hardware/esp8266com/esp8266/tools/sdk/include/espconn.h similarity index 100% rename from hardware/tools/esp8266/sdk/include/espconn.h rename to hardware/esp8266com/esp8266/tools/sdk/include/espconn.h diff --git a/hardware/tools/esp8266/sdk/include/ets_sys.h b/hardware/esp8266com/esp8266/tools/sdk/include/ets_sys.h similarity index 93% rename from hardware/tools/esp8266/sdk/include/ets_sys.h rename to hardware/esp8266com/esp8266/tools/sdk/include/ets_sys.h index b7b79c341..7908699bb 100644 --- a/hardware/tools/esp8266/sdk/include/ets_sys.h +++ b/hardware/esp8266com/esp8266/tools/sdk/include/ets_sys.h @@ -91,10 +91,10 @@ typedef void (*int_handler_t)(void*); ETS_INTR_DISABLE(ETS_GPIO_INUM) -void *pvPortMalloc(size_t xWantedSize); -void *pvPortRealloc(void* ptr, size_t xWantedSize); +void *pvPortMalloc(size_t xWantedSize) __attribute__((malloc, alloc_size(1))); +void *pvPortRealloc(void* ptr, size_t xWantedSize) __attribute__((alloc_size(2))); void pvPortFree(void *ptr); -void *vPortMalloc(size_t xWantedSize); +void *vPortMalloc(size_t xWantedSize) __attribute__((malloc, alloc_size(1))); void vPortFree(void *ptr); void *ets_memcpy(void *dest, const void *src, size_t n); void *ets_memset(void *s, int c, size_t n); diff --git a/hardware/tools/esp8266/sdk/include/gpio.h b/hardware/esp8266com/esp8266/tools/sdk/include/gpio.h similarity index 100% rename from hardware/tools/esp8266/sdk/include/gpio.h rename to hardware/esp8266com/esp8266/tools/sdk/include/gpio.h diff --git a/hardware/tools/esp8266/sdk/include/ip_addr.h b/hardware/esp8266com/esp8266/tools/sdk/include/ip_addr.h similarity index 85% rename from hardware/tools/esp8266/sdk/include/ip_addr.h rename to hardware/esp8266com/esp8266/tools/sdk/include/ip_addr.h index 728a75c46..fc488ea8f 100644 --- a/hardware/tools/esp8266/sdk/include/ip_addr.h +++ b/hardware/esp8266com/esp8266/tools/sdk/include/ip_addr.h @@ -59,11 +59,10 @@ struct ip_info { #define IPADDR_ANY ((uint32)0x00000000UL) uint32 ipaddr_addr(const char *cp); -#define IP2STR(ipaddr) ip4_addr1_16(ipaddr), \ - ip4_addr2_16(ipaddr), \ - ip4_addr3_16(ipaddr), \ - ip4_addr4_16(ipaddr) - +#define IP2STR(addr) (uint8_t)(addr & 0xFF), (uint8_t)((addr >> 8) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), (uint8_t)((addr >> 24) & 0xFF) #define IPSTR "%d.%d.%d.%d" +#define MAC2STR(mac) (uint8_t)mac[0], (uint8_t)mac[1], (uint8_t)mac[2], (uint8_t)mac[3], (uint8_t)mac[4], (uint8_t)mac[5] +#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" + #endif /* __IP_ADDR_H__ */ diff --git a/hardware/tools/esp8266/sdk/include/json/json.h b/hardware/esp8266com/esp8266/tools/sdk/include/json/json.h similarity index 97% rename from hardware/tools/esp8266/sdk/include/json/json.h rename to hardware/esp8266com/esp8266/tools/sdk/include/json/json.h index 45ff40a58..2308b5b7a 100755 --- a/hardware/tools/esp8266/sdk/include/json/json.h +++ b/hardware/esp8266com/esp8266/tools/sdk/include/json/json.h @@ -1,70 +1,70 @@ -/* - * Copyright (c) 2011-2012, Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the Institute 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 INSTITUTE 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 INSTITUTE 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. - * - * This file is part of the Contiki operating system. - */ - -/** - * \file - * A few JSON defines used for parsing and generating JSON. - * \author - * Niclas Finne - * Joakim Eriksson - */ - -#ifndef __JSON_H__ -#define __JSON_H__ - -#define JSON_TYPE_ARRAY '[' -#define JSON_TYPE_OBJECT '{' -#define JSON_TYPE_PAIR ':' -#define JSON_TYPE_PAIR_NAME 'N' /* for N:V pairs */ -#define JSON_TYPE_STRING '"' -#define JSON_TYPE_INT 'I' -#define JSON_TYPE_NUMBER '0' -#define JSON_TYPE_ERROR 0 - -/* how should we handle null vs false - both can be 0? */ -#define JSON_TYPE_NULL 'n' -#define JSON_TYPE_TRUE 't' -#define JSON_TYPE_FALSE 'f' - -#define JSON_TYPE_CALLBACK 'C' - -enum { - JSON_ERROR_OK, - JSON_ERROR_SYNTAX, - JSON_ERROR_UNEXPECTED_ARRAY, - JSON_ERROR_UNEXPECTED_END_OF_ARRAY, - JSON_ERROR_UNEXPECTED_OBJECT, - JSON_ERROR_UNEXPECTED_STRING -}; - -#define JSON_CONTENT_TYPE "application/json" - -#endif /* __JSON_H__ */ +/* + * Copyright (c) 2011-2012, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute 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 INSTITUTE 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 INSTITUTE 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. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * A few JSON defines used for parsing and generating JSON. + * \author + * Niclas Finne + * Joakim Eriksson + */ + +#ifndef __JSON_H__ +#define __JSON_H__ + +#define JSON_TYPE_ARRAY '[' +#define JSON_TYPE_OBJECT '{' +#define JSON_TYPE_PAIR ':' +#define JSON_TYPE_PAIR_NAME 'N' /* for N:V pairs */ +#define JSON_TYPE_STRING '"' +#define JSON_TYPE_INT 'I' +#define JSON_TYPE_NUMBER '0' +#define JSON_TYPE_ERROR 0 + +/* how should we handle null vs false - both can be 0? */ +#define JSON_TYPE_NULL 'n' +#define JSON_TYPE_TRUE 't' +#define JSON_TYPE_FALSE 'f' + +#define JSON_TYPE_CALLBACK 'C' + +enum { + JSON_ERROR_OK, + JSON_ERROR_SYNTAX, + JSON_ERROR_UNEXPECTED_ARRAY, + JSON_ERROR_UNEXPECTED_END_OF_ARRAY, + JSON_ERROR_UNEXPECTED_OBJECT, + JSON_ERROR_UNEXPECTED_STRING +}; + +#define JSON_CONTENT_TYPE "application/json" + +#endif /* __JSON_H__ */ diff --git a/hardware/tools/esp8266/sdk/include/json/jsonparse.h b/hardware/esp8266com/esp8266/tools/sdk/include/json/jsonparse.h similarity index 97% rename from hardware/tools/esp8266/sdk/include/json/jsonparse.h rename to hardware/esp8266com/esp8266/tools/sdk/include/json/jsonparse.h index b6082144f..e1cb67a46 100755 --- a/hardware/tools/esp8266/sdk/include/json/jsonparse.h +++ b/hardware/esp8266com/esp8266/tools/sdk/include/json/jsonparse.h @@ -1,94 +1,94 @@ -/* - * Copyright (c) 2011-2012, Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the Institute 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 INSTITUTE 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 INSTITUTE 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. - * - * This file is part of the Contiki operating system. - */ - -#ifndef __JSONPARSE_H__ -#define __JSONPARSE_H__ - -#include "c_types.h" -#include "json/json.h" - -#ifdef JSONPARSE_CONF_MAX_DEPTH -#define JSONPARSE_MAX_DEPTH JSONPARSE_CONF_MAX_DEPTH -#else -#define JSONPARSE_MAX_DEPTH 10 -#endif - -struct jsonparse_state { - const char *json; - int pos; - int len; - int depth; - /* for handling atomic values */ - int vstart; - int vlen; - char vtype; - char error; - char stack[JSONPARSE_MAX_DEPTH]; -}; - -/** - * \brief Initialize a JSON parser state. - * \param state A pointer to a JSON parser state - * \param json The string to parse as JSON - * \param len The length of the string to parse - * - * This function initializes a JSON parser state for - * parsing a string as JSON. - */ -void jsonparse_setup(struct jsonparse_state *state, const char *json, - int len); - -/* move to next JSON element */ -int jsonparse_next(struct jsonparse_state *state); - -/* copy the current JSON value into the specified buffer */ -int jsonparse_copy_value(struct jsonparse_state *state, char *buf, - int buf_size); - -/* get the current JSON value parsed as an int */ -int jsonparse_get_value_as_int(struct jsonparse_state *state); - -/* get the current JSON value parsed as a long */ -long jsonparse_get_value_as_long(struct jsonparse_state *state); - -/* get the current JSON value parsed as a unsigned long */ -unsigned long jsonparse_get_value_as_ulong(struct jsonparse_state *state); - -/* get the length of the current JSON value */ -int jsonparse_get_len(struct jsonparse_state *state); - -/* get the type of the current JSON value */ -int jsonparse_get_type(struct jsonparse_state *state); - -/* compare the JSON value with the specified string */ -int jsonparse_strcmp_value(struct jsonparse_state *state, const char *str); - -#endif /* __JSONPARSE_H__ */ +/* + * Copyright (c) 2011-2012, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute 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 INSTITUTE 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 INSTITUTE 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. + * + * This file is part of the Contiki operating system. + */ + +#ifndef __JSONPARSE_H__ +#define __JSONPARSE_H__ + +#include "c_types.h" +#include "json/json.h" + +#ifdef JSONPARSE_CONF_MAX_DEPTH +#define JSONPARSE_MAX_DEPTH JSONPARSE_CONF_MAX_DEPTH +#else +#define JSONPARSE_MAX_DEPTH 10 +#endif + +struct jsonparse_state { + const char *json; + int pos; + int len; + int depth; + /* for handling atomic values */ + int vstart; + int vlen; + char vtype; + char error; + char stack[JSONPARSE_MAX_DEPTH]; +}; + +/** + * \brief Initialize a JSON parser state. + * \param state A pointer to a JSON parser state + * \param json The string to parse as JSON + * \param len The length of the string to parse + * + * This function initializes a JSON parser state for + * parsing a string as JSON. + */ +void jsonparse_setup(struct jsonparse_state *state, const char *json, + int len); + +/* move to next JSON element */ +int jsonparse_next(struct jsonparse_state *state); + +/* copy the current JSON value into the specified buffer */ +int jsonparse_copy_value(struct jsonparse_state *state, char *buf, + int buf_size); + +/* get the current JSON value parsed as an int */ +int jsonparse_get_value_as_int(struct jsonparse_state *state); + +/* get the current JSON value parsed as a long */ +long jsonparse_get_value_as_long(struct jsonparse_state *state); + +/* get the current JSON value parsed as a unsigned long */ +unsigned long jsonparse_get_value_as_ulong(struct jsonparse_state *state); + +/* get the length of the current JSON value */ +int jsonparse_get_len(struct jsonparse_state *state); + +/* get the type of the current JSON value */ +int jsonparse_get_type(struct jsonparse_state *state); + +/* compare the JSON value with the specified string */ +int jsonparse_strcmp_value(struct jsonparse_state *state, const char *str); + +#endif /* __JSONPARSE_H__ */ diff --git a/hardware/tools/esp8266/sdk/include/json/jsontree.h b/hardware/esp8266com/esp8266/tools/sdk/include/json/jsontree.h similarity index 97% rename from hardware/tools/esp8266/sdk/include/json/jsontree.h rename to hardware/esp8266com/esp8266/tools/sdk/include/json/jsontree.h index d434d42d8..0ffe9d154 100755 --- a/hardware/tools/esp8266/sdk/include/json/jsontree.h +++ b/hardware/esp8266com/esp8266/tools/sdk/include/json/jsontree.h @@ -1,145 +1,145 @@ -/* - * Copyright (c) 2011-2012, Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the Institute 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 INSTITUTE 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 INSTITUTE 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. - * - * This file is part of the Contiki operating system. - */ - -/** - * \file - * JSON output generation - * \author - * Niclas Finne - * Joakim Eriksson - */ - -#ifndef __JSONTREE_H__ -#define __JSONTREE_H__ - -#include "c_types.h" -#include "json/json.h" - -#ifdef JSONTREE_CONF_MAX_DEPTH -#define JSONTREE_MAX_DEPTH JSONTREE_CONF_MAX_DEPTH -#else -#define JSONTREE_MAX_DEPTH 10 -#endif /* JSONTREE_CONF_MAX_DEPTH */ - -struct jsontree_context { - struct jsontree_value *values[JSONTREE_MAX_DEPTH]; - uint16_t index[JSONTREE_MAX_DEPTH]; - int (* putchar)(int); - uint8_t depth; - uint8_t path; - int callback_state; -}; - -struct jsontree_value { - uint8_t type; - /* followed by a value */ -}; - -struct jsontree_string { - uint8_t type; - const char *value; -}; - -struct jsontree_int { - uint8_t type; - int value; -}; - -/* NOTE: the jsontree_callback set will receive a jsonparse state */ -struct jsonparse_state; -struct jsontree_callback { - uint8_t type; - int (* output)(struct jsontree_context *js_ctx); - int (* set)(struct jsontree_context *js_ctx, struct jsonparse_state *parser); -}; - -struct jsontree_pair { - const char *name; - struct jsontree_value *value; -}; - -struct jsontree_object { - uint8_t type; - uint8_t count; - struct jsontree_pair *pairs; -}; - -struct jsontree_array { - uint8_t type; - uint8_t count; - struct jsontree_value **values; -}; - -#define JSONTREE_STRING(text) {JSON_TYPE_STRING, (text)} -#define JSONTREE_PAIR(name, value) {(name), (struct jsontree_value *)(value)} -#define JSONTREE_CALLBACK(output, set) {JSON_TYPE_CALLBACK, (output), (set)} - -#define JSONTREE_OBJECT(name, ...) \ - static struct jsontree_pair jsontree_pair_##name[] = {__VA_ARGS__}; \ - static struct jsontree_object name = { \ - JSON_TYPE_OBJECT, \ - sizeof(jsontree_pair_##name)/sizeof(struct jsontree_pair), \ - jsontree_pair_##name } - -#define JSONTREE_PAIR_ARRAY(value) (struct jsontree_value *)(value) -#define JSONTREE_ARRAY(name, ...) \ - static struct jsontree_value* jsontree_value_##name[] = {__VA_ARGS__}; \ - static struct jsontree_array name = { \ - JSON_TYPE_ARRAY, \ - sizeof(jsontree_value_##name)/sizeof(struct jsontree_value*), \ - jsontree_value_##name } - -#define JSONTREE_OBJECT_EXT(name, ...) \ - static struct jsontree_pair jsontree_pair_##name[] = {__VA_ARGS__}; \ - struct jsontree_object name = { \ - JSON_TYPE_OBJECT, \ - sizeof(jsontree_pair_##name)/sizeof(struct jsontree_pair), \ - jsontree_pair_##name } - -void jsontree_setup(struct jsontree_context *js_ctx, - struct jsontree_value *root, int (* putchar)(int)); -void jsontree_reset(struct jsontree_context *js_ctx); - -const char *jsontree_path_name(const struct jsontree_context *js_ctx, - int depth); - -void jsontree_write_int(const struct jsontree_context *js_ctx, int value); -void jsontree_write_int_array(const struct jsontree_context *js_ctx, const int *text, uint32 length); - -void jsontree_write_atom(const struct jsontree_context *js_ctx, - const char *text); -void jsontree_write_string(const struct jsontree_context *js_ctx, - const char *text); -int jsontree_print_next(struct jsontree_context *js_ctx); -struct jsontree_value *jsontree_find_next(struct jsontree_context *js_ctx, - int type); - -#endif /* __JSONTREE_H__ */ +/* + * Copyright (c) 2011-2012, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute 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 INSTITUTE 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 INSTITUTE 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. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * JSON output generation + * \author + * Niclas Finne + * Joakim Eriksson + */ + +#ifndef __JSONTREE_H__ +#define __JSONTREE_H__ + +#include "c_types.h" +#include "json/json.h" + +#ifdef JSONTREE_CONF_MAX_DEPTH +#define JSONTREE_MAX_DEPTH JSONTREE_CONF_MAX_DEPTH +#else +#define JSONTREE_MAX_DEPTH 10 +#endif /* JSONTREE_CONF_MAX_DEPTH */ + +struct jsontree_context { + struct jsontree_value *values[JSONTREE_MAX_DEPTH]; + uint16_t index[JSONTREE_MAX_DEPTH]; + int (* putchar)(int); + uint8_t depth; + uint8_t path; + int callback_state; +}; + +struct jsontree_value { + uint8_t type; + /* followed by a value */ +}; + +struct jsontree_string { + uint8_t type; + const char *value; +}; + +struct jsontree_int { + uint8_t type; + int value; +}; + +/* NOTE: the jsontree_callback set will receive a jsonparse state */ +struct jsonparse_state; +struct jsontree_callback { + uint8_t type; + int (* output)(struct jsontree_context *js_ctx); + int (* set)(struct jsontree_context *js_ctx, struct jsonparse_state *parser); +}; + +struct jsontree_pair { + const char *name; + struct jsontree_value *value; +}; + +struct jsontree_object { + uint8_t type; + uint8_t count; + struct jsontree_pair *pairs; +}; + +struct jsontree_array { + uint8_t type; + uint8_t count; + struct jsontree_value **values; +}; + +#define JSONTREE_STRING(text) {JSON_TYPE_STRING, (text)} +#define JSONTREE_PAIR(name, value) {(name), (struct jsontree_value *)(value)} +#define JSONTREE_CALLBACK(output, set) {JSON_TYPE_CALLBACK, (output), (set)} + +#define JSONTREE_OBJECT(name, ...) \ + static struct jsontree_pair jsontree_pair_##name[] = {__VA_ARGS__}; \ + static struct jsontree_object name = { \ + JSON_TYPE_OBJECT, \ + sizeof(jsontree_pair_##name)/sizeof(struct jsontree_pair), \ + jsontree_pair_##name } + +#define JSONTREE_PAIR_ARRAY(value) (struct jsontree_value *)(value) +#define JSONTREE_ARRAY(name, ...) \ + static struct jsontree_value* jsontree_value_##name[] = {__VA_ARGS__}; \ + static struct jsontree_array name = { \ + JSON_TYPE_ARRAY, \ + sizeof(jsontree_value_##name)/sizeof(struct jsontree_value*), \ + jsontree_value_##name } + +#define JSONTREE_OBJECT_EXT(name, ...) \ + static struct jsontree_pair jsontree_pair_##name[] = {__VA_ARGS__}; \ + struct jsontree_object name = { \ + JSON_TYPE_OBJECT, \ + sizeof(jsontree_pair_##name)/sizeof(struct jsontree_pair), \ + jsontree_pair_##name } + +void jsontree_setup(struct jsontree_context *js_ctx, + struct jsontree_value *root, int (* putchar)(int)); +void jsontree_reset(struct jsontree_context *js_ctx); + +const char *jsontree_path_name(const struct jsontree_context *js_ctx, + int depth); + +void jsontree_write_int(const struct jsontree_context *js_ctx, int value); +void jsontree_write_int_array(const struct jsontree_context *js_ctx, const int *text, uint32 length); + +void jsontree_write_atom(const struct jsontree_context *js_ctx, + const char *text); +void jsontree_write_string(const struct jsontree_context *js_ctx, + const char *text); +int jsontree_print_next(struct jsontree_context *js_ctx); +struct jsontree_value *jsontree_find_next(struct jsontree_context *js_ctx, + int type); + +#endif /* __JSONTREE_H__ */ diff --git a/hardware/tools/esp8266/sdk/include/mem.h b/hardware/esp8266com/esp8266/tools/sdk/include/mem.h similarity index 100% rename from hardware/tools/esp8266/sdk/include/mem.h rename to hardware/esp8266com/esp8266/tools/sdk/include/mem.h diff --git a/hardware/tools/esp8266/sdk/include/os_type.h b/hardware/esp8266com/esp8266/tools/sdk/include/os_type.h similarity index 100% rename from hardware/tools/esp8266/sdk/include/os_type.h rename to hardware/esp8266com/esp8266/tools/sdk/include/os_type.h diff --git a/hardware/tools/esp8266/sdk/include/osapi.h b/hardware/esp8266com/esp8266/tools/sdk/include/osapi.h similarity index 94% rename from hardware/tools/esp8266/sdk/include/osapi.h rename to hardware/esp8266com/esp8266/tools/sdk/include/osapi.h index 6935388c5..11e03803f 100644 --- a/hardware/tools/esp8266/sdk/include/osapi.h +++ b/hardware/esp8266com/esp8266/tools/sdk/include/osapi.h @@ -50,7 +50,7 @@ os_printf_plus(flash_str, ##__VA_ARGS__); \ } while(0) #else -extern int os_printf_plus(const char * format, ...); +extern int os_printf_plus(const char * format, ...) __attribute__ ((format (printf, 1, 2))); #define os_printf os_printf_plus #endif diff --git a/hardware/tools/esp8266/sdk/include/ping.h b/hardware/esp8266com/esp8266/tools/sdk/include/ping.h similarity index 100% rename from hardware/tools/esp8266/sdk/include/ping.h rename to hardware/esp8266com/esp8266/tools/sdk/include/ping.h diff --git a/hardware/tools/esp8266/sdk/include/queue.h b/hardware/esp8266com/esp8266/tools/sdk/include/queue.h similarity index 100% rename from hardware/tools/esp8266/sdk/include/queue.h rename to hardware/esp8266com/esp8266/tools/sdk/include/queue.h diff --git a/hardware/tools/esp8266/sdk/include/smartconfig.h b/hardware/esp8266com/esp8266/tools/sdk/include/smartconfig.h similarity index 100% rename from hardware/tools/esp8266/sdk/include/smartconfig.h rename to hardware/esp8266com/esp8266/tools/sdk/include/smartconfig.h diff --git a/hardware/tools/esp8266/sdk/include/sntp.h b/hardware/esp8266com/esp8266/tools/sdk/include/sntp.h similarity index 100% rename from hardware/tools/esp8266/sdk/include/sntp.h rename to hardware/esp8266com/esp8266/tools/sdk/include/sntp.h diff --git a/hardware/tools/esp8266/sdk/include/spi_flash.h b/hardware/esp8266com/esp8266/tools/sdk/include/spi_flash.h similarity index 92% rename from hardware/tools/esp8266/sdk/include/spi_flash.h rename to hardware/esp8266com/esp8266/tools/sdk/include/spi_flash.h index 12dd6e174..347e1b920 100644 --- a/hardware/tools/esp8266/sdk/include/spi_flash.h +++ b/hardware/esp8266com/esp8266/tools/sdk/include/spi_flash.h @@ -23,6 +23,8 @@ typedef struct{ #define SPI_FLASH_SEC_SIZE 4096 +extern SpiFlashChip * flashchip; // in ram ROM-BIOS + uint32 spi_flash_get_id(void); SpiFlashOpResult spi_flash_erase_sector(uint16 sec); SpiFlashOpResult spi_flash_write(uint32 des_addr, uint32 *src_addr, uint32 size); diff --git a/hardware/tools/esp8266/sdk/include/uart_register.h b/hardware/esp8266com/esp8266/tools/sdk/include/uart_register.h similarity index 100% rename from hardware/tools/esp8266/sdk/include/uart_register.h rename to hardware/esp8266com/esp8266/tools/sdk/include/uart_register.h diff --git a/hardware/tools/esp8266/sdk/include/upgrade.h b/hardware/esp8266com/esp8266/tools/sdk/include/upgrade.h similarity index 100% rename from hardware/tools/esp8266/sdk/include/upgrade.h rename to hardware/esp8266com/esp8266/tools/sdk/include/upgrade.h diff --git a/hardware/tools/esp8266/sdk/include/user_interface.h b/hardware/esp8266com/esp8266/tools/sdk/include/user_interface.h similarity index 100% rename from hardware/tools/esp8266/sdk/include/user_interface.h rename to hardware/esp8266com/esp8266/tools/sdk/include/user_interface.h diff --git a/hardware/tools/esp8266/sdk/ld/eagle.app.v6.ld b/hardware/esp8266com/esp8266/tools/sdk/ld/eagle.app.v6.common.ld similarity index 94% rename from hardware/tools/esp8266/sdk/ld/eagle.app.v6.ld rename to hardware/esp8266com/esp8266/tools/sdk/ld/eagle.app.v6.common.ld index 6052b35ae..986b441ff 100644 --- a/hardware/tools/esp8266/sdk/ld/eagle.app.v6.ld +++ b/hardware/esp8266com/esp8266/tools/sdk/ld/eagle.app.v6.common.ld @@ -1,12 +1,5 @@ /* This linker script generated from xt-genldscripts.tpp for LSP . */ /* Linker Script for ld -N */ -MEMORY -{ - dport0_0_seg : org = 0x3FF00000, len = 0x10 - dram0_0_seg : org = 0x3FFE8000, len = 0x14000 - iram1_0_seg : org = 0x40100000, len = 0x8000 - irom0_0_seg : org = 0x40210000, len = 0x6B000 -} PHDRS { @@ -152,11 +145,13 @@ SECTIONS { _irom0_text_start = ABSOLUTE(.); *core_esp8266_*.o(.literal*, .text*) + *spiffs*.o(.literal*, .text*) *.cpp.o(.literal*, .text*) *libm.a:(.literal .text .literal.* .text.*) *libsmartconfig.a:(.literal .text .literal.* .text.*) *(.irom0.literal .irom.literal .irom.text.literal .irom0.text .irom.text) _irom0_text_end = ABSOLUTE(.); + _flash_code_end = ABSOLUTE(.); } >irom0_0_seg :irom0_0_phdr .text : ALIGN(4) diff --git a/hardware/esp8266com/esp8266/tools/sdk/ld/eagle.flash.16m.ld b/hardware/esp8266com/esp8266/tools/sdk/ld/eagle.flash.16m.ld new file mode 100644 index 000000000..b1624e769 --- /dev/null +++ b/hardware/esp8266com/esp8266/tools/sdk/ld/eagle.flash.16m.ld @@ -0,0 +1,17 @@ +/* Flash Split for 16M chips */ +/* irom0 940KB */ +/* eeprom 20KB */ +/* spiffs 15MB */ + +MEMORY +{ + dport0_0_seg : org = 0x3FF00000, len = 0x10 + dram0_0_seg : org = 0x3FFE8000, len = 0x14000 + iram1_0_seg : org = 0x40100000, len = 0x8000 + irom0_0_seg : org = 0x40210000, len = 0xEB000 +} + +PROVIDE ( _SPIFFS_start = 0x40300000 ); +PROVIDE ( _SPIFFS_end = 0x41200000 ); + +INCLUDE "../ld/eagle.app.v6.common.ld" diff --git a/hardware/esp8266com/esp8266/tools/sdk/ld/eagle.flash.1m128.ld b/hardware/esp8266com/esp8266/tools/sdk/ld/eagle.flash.1m128.ld new file mode 100644 index 000000000..ddd57a57b --- /dev/null +++ b/hardware/esp8266com/esp8266/tools/sdk/ld/eagle.flash.1m128.ld @@ -0,0 +1,17 @@ +/* Flash Split for 1M chips */ +/* irom0 812KB */ +/* spiffs 128KB */ +/* eeprom 20KB */ + +MEMORY +{ + dport0_0_seg : org = 0x3FF00000, len = 0x10 + dram0_0_seg : org = 0x3FFE8000, len = 0x14000 + iram1_0_seg : org = 0x40100000, len = 0x8000 + irom0_0_seg : org = 0x40210000, len = 0xCB000 +} + +PROVIDE ( _SPIFFS_start = 0x402DB000 ); +PROVIDE ( _SPIFFS_end = 0x402FB000 ); + +INCLUDE "../ld/eagle.app.v6.common.ld" diff --git a/hardware/esp8266com/esp8266/tools/sdk/ld/eagle.flash.1m256.ld b/hardware/esp8266com/esp8266/tools/sdk/ld/eagle.flash.1m256.ld new file mode 100644 index 000000000..57b6a33fb --- /dev/null +++ b/hardware/esp8266com/esp8266/tools/sdk/ld/eagle.flash.1m256.ld @@ -0,0 +1,17 @@ +/* Flash Split for 1M chips */ +/* irom0 684KB */ +/* spiffs 256KB */ +/* eeprom 20KB */ + +MEMORY +{ + dport0_0_seg : org = 0x3FF00000, len = 0x10 + dram0_0_seg : org = 0x3FFE8000, len = 0x14000 + iram1_0_seg : org = 0x40100000, len = 0x8000 + irom0_0_seg : org = 0x40210000, len = 0xAB000 +} + +PROVIDE ( _SPIFFS_start = 0x402BB000 ); +PROVIDE ( _SPIFFS_end = 0x402FB000 ); + +INCLUDE "../ld/eagle.app.v6.common.ld" diff --git a/hardware/esp8266com/esp8266/tools/sdk/ld/eagle.flash.1m512.ld b/hardware/esp8266com/esp8266/tools/sdk/ld/eagle.flash.1m512.ld new file mode 100644 index 000000000..1ffd7e678 --- /dev/null +++ b/hardware/esp8266com/esp8266/tools/sdk/ld/eagle.flash.1m512.ld @@ -0,0 +1,17 @@ +/* Flash Split for 1M chips */ +/* irom0 428KB */ +/* spiffs 512KB */ +/* eeprom 20KB */ + +MEMORY +{ + dport0_0_seg : org = 0x3FF00000, len = 0x10 + dram0_0_seg : org = 0x3FFE8000, len = 0x14000 + iram1_0_seg : org = 0x40100000, len = 0x8000 + irom0_0_seg : org = 0x40210000, len = 0x6B000 +} + +PROVIDE ( _SPIFFS_start = 0x4027B000 ); +PROVIDE ( _SPIFFS_end = 0x402FB000 ); + +INCLUDE "../ld/eagle.app.v6.common.ld" diff --git a/hardware/esp8266com/esp8266/tools/sdk/ld/eagle.flash.1m64.ld b/hardware/esp8266com/esp8266/tools/sdk/ld/eagle.flash.1m64.ld new file mode 100644 index 000000000..ca3d64c67 --- /dev/null +++ b/hardware/esp8266com/esp8266/tools/sdk/ld/eagle.flash.1m64.ld @@ -0,0 +1,17 @@ +/* Flash Split for 1M chips */ +/* irom0 876KB */ +/* spiffs 64KB */ +/* eeprom 20KB */ + +MEMORY +{ + dport0_0_seg : org = 0x3FF00000, len = 0x10 + dram0_0_seg : org = 0x3FFE8000, len = 0x14000 + iram1_0_seg : org = 0x40100000, len = 0x8000 + irom0_0_seg : org = 0x40210000, len = 0xDB000 +} + +PROVIDE ( _SPIFFS_start = 0x402EB000 ); +PROVIDE ( _SPIFFS_end = 0x402FB000 ); + +INCLUDE "../ld/eagle.app.v6.common.ld" diff --git a/hardware/esp8266com/esp8266/tools/sdk/ld/eagle.flash.2m.ld b/hardware/esp8266com/esp8266/tools/sdk/ld/eagle.flash.2m.ld new file mode 100644 index 000000000..cd6af2770 --- /dev/null +++ b/hardware/esp8266com/esp8266/tools/sdk/ld/eagle.flash.2m.ld @@ -0,0 +1,17 @@ +/* Flash Split for 2M chips */ +/* irom0 960KB */ +/* spiffs 1004KB */ +/* eeprom 20KB */ + +MEMORY +{ + dport0_0_seg : org = 0x3FF00000, len = 0x10 + dram0_0_seg : org = 0x3FFE8000, len = 0x14000 + iram1_0_seg : org = 0x40100000, len = 0x8000 + irom0_0_seg : org = 0x40210000, len = 0xF0000 +} + +PROVIDE ( _SPIFFS_start = 0x40300000 ); +PROVIDE ( _SPIFFS_end = 0x403FB000 ); + +INCLUDE "../ld/eagle.app.v6.common.ld" diff --git a/hardware/esp8266com/esp8266/tools/sdk/ld/eagle.flash.4m.ld b/hardware/esp8266com/esp8266/tools/sdk/ld/eagle.flash.4m.ld new file mode 100644 index 000000000..7df2fa8ad --- /dev/null +++ b/hardware/esp8266com/esp8266/tools/sdk/ld/eagle.flash.4m.ld @@ -0,0 +1,17 @@ +/* Flash Split for 4M chips */ +/* irom0 960KB */ +/* spiffs 3052KB */ +/* eeprom 20KB */ + +MEMORY +{ + dport0_0_seg : org = 0x3FF00000, len = 0x10 + dram0_0_seg : org = 0x3FFE8000, len = 0x14000 + iram1_0_seg : org = 0x40100000, len = 0x8000 + irom0_0_seg : org = 0x40210000, len = 0xF0000 +} + +PROVIDE ( _SPIFFS_start = 0x40300000 ); +PROVIDE ( _SPIFFS_end = 0x405FB000 ); + +INCLUDE "../ld/eagle.app.v6.common.ld" diff --git a/hardware/esp8266com/esp8266/tools/sdk/ld/eagle.flash.512k.ld b/hardware/esp8266com/esp8266/tools/sdk/ld/eagle.flash.512k.ld new file mode 100644 index 000000000..05160fe95 --- /dev/null +++ b/hardware/esp8266com/esp8266/tools/sdk/ld/eagle.flash.512k.ld @@ -0,0 +1,17 @@ +/* Flash Split for 512K chips */ +/* irom0 364KB */ +/* spiffs 64KB */ +/* eeprom 20KB */ + +MEMORY +{ + dport0_0_seg : org = 0x3FF00000, len = 0x10 + dram0_0_seg : org = 0x3FFE8000, len = 0x14000 + iram1_0_seg : org = 0x40100000, len = 0x8000 + irom0_0_seg : org = 0x40210000, len = 0x5B000 +} + +PROVIDE ( _SPIFFS_start = 0x4026B000 ); +PROVIDE ( _SPIFFS_end = 0x4027B000 ); + +INCLUDE "../ld/eagle.app.v6.common.ld" diff --git a/hardware/esp8266com/esp8266/tools/sdk/ld/eagle.flash.8m.ld b/hardware/esp8266com/esp8266/tools/sdk/ld/eagle.flash.8m.ld new file mode 100644 index 000000000..b3eeddf22 --- /dev/null +++ b/hardware/esp8266com/esp8266/tools/sdk/ld/eagle.flash.8m.ld @@ -0,0 +1,17 @@ +/* Flash Split for 8M chips */ +/* irom0 940KB */ +/* eeprom 20KB */ +/* spiffs 7MB */ + +MEMORY +{ + dport0_0_seg : org = 0x3FF00000, len = 0x10 + dram0_0_seg : org = 0x3FFE8000, len = 0x14000 + iram1_0_seg : org = 0x40100000, len = 0x8000 + irom0_0_seg : org = 0x40210000, len = 0xEB000 +} + +PROVIDE ( _SPIFFS_start = 0x40300000 ); +PROVIDE ( _SPIFFS_end = 0x40A00000 ); + +INCLUDE "../ld/eagle.app.v6.common.ld" diff --git a/hardware/tools/esp8266/sdk/ld/eagle.rom.addr.v6.ld b/hardware/esp8266com/esp8266/tools/sdk/ld/eagle.rom.addr.v6.ld similarity index 100% rename from hardware/tools/esp8266/sdk/ld/eagle.rom.addr.v6.ld rename to hardware/esp8266com/esp8266/tools/sdk/ld/eagle.rom.addr.v6.ld diff --git a/hardware/tools/esp8266/sdk/lib/libhal.a b/hardware/esp8266com/esp8266/tools/sdk/lib/libhal.a similarity index 100% rename from hardware/tools/esp8266/sdk/lib/libhal.a rename to hardware/esp8266com/esp8266/tools/sdk/lib/libhal.a diff --git a/hardware/tools/esp8266/sdk/lib/libjson.a b/hardware/esp8266com/esp8266/tools/sdk/lib/libjson.a similarity index 100% rename from hardware/tools/esp8266/sdk/lib/libjson.a rename to hardware/esp8266com/esp8266/tools/sdk/lib/libjson.a diff --git a/hardware/tools/esp8266/sdk/lib/liblwip.a b/hardware/esp8266com/esp8266/tools/sdk/lib/liblwip.a similarity index 100% rename from hardware/tools/esp8266/sdk/lib/liblwip.a rename to hardware/esp8266com/esp8266/tools/sdk/lib/liblwip.a diff --git a/hardware/tools/esp8266/sdk/lib/libmain.a b/hardware/esp8266com/esp8266/tools/sdk/lib/libmain.a similarity index 100% rename from hardware/tools/esp8266/sdk/lib/libmain.a rename to hardware/esp8266com/esp8266/tools/sdk/lib/libmain.a diff --git a/hardware/tools/esp8266/sdk/lib/libnet80211.a b/hardware/esp8266com/esp8266/tools/sdk/lib/libnet80211.a similarity index 100% rename from hardware/tools/esp8266/sdk/lib/libnet80211.a rename to hardware/esp8266com/esp8266/tools/sdk/lib/libnet80211.a diff --git a/hardware/tools/esp8266/sdk/lib/libphy.a b/hardware/esp8266com/esp8266/tools/sdk/lib/libphy.a similarity index 100% rename from hardware/tools/esp8266/sdk/lib/libphy.a rename to hardware/esp8266com/esp8266/tools/sdk/lib/libphy.a diff --git a/hardware/tools/esp8266/sdk/lib/libpp.a b/hardware/esp8266com/esp8266/tools/sdk/lib/libpp.a similarity index 100% rename from hardware/tools/esp8266/sdk/lib/libpp.a rename to hardware/esp8266com/esp8266/tools/sdk/lib/libpp.a diff --git a/hardware/tools/esp8266/sdk/lib/libsmartconfig.a b/hardware/esp8266com/esp8266/tools/sdk/lib/libsmartconfig.a similarity index 100% rename from hardware/tools/esp8266/sdk/lib/libsmartconfig.a rename to hardware/esp8266com/esp8266/tools/sdk/lib/libsmartconfig.a diff --git a/hardware/tools/esp8266/sdk/lib/libssc.a b/hardware/esp8266com/esp8266/tools/sdk/lib/libssc.a similarity index 100% rename from hardware/tools/esp8266/sdk/lib/libssc.a rename to hardware/esp8266com/esp8266/tools/sdk/lib/libssc.a diff --git a/hardware/tools/esp8266/sdk/lib/libssl.a b/hardware/esp8266com/esp8266/tools/sdk/lib/libssl.a similarity index 100% rename from hardware/tools/esp8266/sdk/lib/libssl.a rename to hardware/esp8266com/esp8266/tools/sdk/lib/libssl.a diff --git a/hardware/tools/esp8266/sdk/lib/libupgrade.a b/hardware/esp8266com/esp8266/tools/sdk/lib/libupgrade.a similarity index 100% rename from hardware/tools/esp8266/sdk/lib/libupgrade.a rename to hardware/esp8266com/esp8266/tools/sdk/lib/libupgrade.a diff --git a/hardware/tools/esp8266/sdk/lib/libwpa.a b/hardware/esp8266com/esp8266/tools/sdk/lib/libwpa.a similarity index 100% rename from hardware/tools/esp8266/sdk/lib/libwpa.a rename to hardware/esp8266com/esp8266/tools/sdk/lib/libwpa.a diff --git a/hardware/tools/esp8266/sdk/version b/hardware/esp8266com/esp8266/tools/sdk/version similarity index 100% rename from hardware/tools/esp8266/sdk/version rename to hardware/esp8266com/esp8266/tools/sdk/version diff --git a/hardware/platform.keys.rewrite.txt b/hardware/platform.keys.rewrite.txt new file mode 100644 index 000000000..e14de1e6d --- /dev/null +++ b/hardware/platform.keys.rewrite.txt @@ -0,0 +1,17 @@ +old.0.compiler.path={runtime.ide.path}/hardware/tools/avr/bin/ +new.0.compiler.path={runtime.tools.avr-gcc.path}/bin/ + +added.tools.avrdude.path={runtime.tools.avrdude.path} + +old.1.tools.avrdude.cmd.path={runtime.ide.path}/hardware/tools/avr/bin/avrdude +new.1.tools.avrdude.cmd.path={path}/bin/avrdude + +old.2.tools.avrdude.config.path={runtime.ide.path}/hardware/tools/avr/etc/avrdude.conf +new.2.tools.avrdude.config.path={path}/etc/avrdude.conf + +old.3.compiler.path={runtime.ide.path}/hardware/tools/gcc-arm-none-eabi-4.8.3-2014q1/bin/ +new.3.compiler.path={runtime.tools.arm-none-eabi-gcc.path}/bin/ + +old.4.tools.bossac.path={runtime.ide.path}/hardware/tools +new.4.tools.bossac.path={runtime.tools.bossac.path} + diff --git a/lib_sync b/lib_sync new file mode 100755 index 000000000..63419b00d --- /dev/null +++ b/lib_sync @@ -0,0 +1,48 @@ +#!/bin/bash -ex + +git checkout master + +LIB=$1 + +git branch lib_$LIB +git checkout lib_$LIB + +git filter-branch -f --prune-empty --subdirectory-filter libraries/$LIB lib_$LIB + +cd ../libraries +mkdir $LIB +cd $LIB + +git init + +git pull ../../Arduino lib_$LIB + +git config user.email f.fissore@arduino.cc + +git filter-branch -f --commit-filter 'if [ "$GIT_AUTHOR_EMAIL" = "f.vanzati@gmail.com" ]; + then export GIT_AUTHOR_EMAIL=f.vanzati@arduino.cc; + fi; git commit-tree "$@"' +git filter-branch -f --commit-filter 'if [ "$GIT_AUTHOR_EMAIL" = "federico@fissore.org" ]; + then export GIT_AUTHOR_EMAIL=f.fissore@arduino.cc; + fi; git commit-tree "$@"' +git filter-branch -f --commit-filter 'if [ "$GIT_AUTHOR_EMAIL" = "c.maglie@bug.st" ]; + then export GIT_AUTHOR_EMAIL=c.maglie@arduino.cc; + fi; git commit-tree "$@"' +git filter-branch -f --commit-filter 'if [ "$GIT_AUTHOR_EMAIL" = "tigoe@tigoemac.itp.tsoa.nyu.edu" ]; + then export GIT_AUTHOR_EMAIL=t.igoe@arduino.cc; + fi; git commit-tree "$@"' +git filter-branch -f --commit-filter 'if [ "$GIT_AUTHOR_EMAIL" = "tom.igoe@gmail.com" ]; + then export GIT_AUTHOR_EMAIL=t.igoe@arduino.cc; + fi; git commit-tree "$@"' +git filter-branch -f --commit-filter 'if [ "$GIT_AUTHOR_EMAIL" = "facchinm@users.noreply.github.com" ]; + then export GIT_AUTHOR_EMAIL=m.facchin@arduino.cc; + fi; git commit-tree "$@"' + +git remote add origin git@github.com:arduino-libraries/$LIB.git +git fetch --all + +cd ../../Arduino + +git checkout master +git branch -D lib_$LIB + diff --git a/libraries/Audio/README.adoc b/libraries/Audio/README.adoc index 0da2cd095..77f06bf0e 100644 --- a/libraries/Audio/README.adoc +++ b/libraries/Audio/README.adoc @@ -7,7 +7,7 @@ http://arduino.cc/en/Reference/Audio == License == -Copyright (c) Arduino LLC. All right reserved. +Copyright (c) 2012 Arduino LLC. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public diff --git a/libraries/Audio/keywords.txt b/libraries/Audio/keywords.txt index b95d21712..25cc67af6 100644 --- a/libraries/Audio/keywords.txt +++ b/libraries/Audio/keywords.txt @@ -6,7 +6,7 @@ # Datatypes (KEYWORD1) ####################################### -Audio KEYWORD1 +Audio KEYWORD1 Audio ####################################### # Methods and Functions (KEYWORD2) diff --git a/libraries/Audio/library.properties b/libraries/Audio/library.properties index bef3c8683..3caa70522 100644 --- a/libraries/Audio/library.properties +++ b/libraries/Audio/library.properties @@ -1,5 +1,5 @@ name=Audio -version=1.0 +version=1.0.2 author=Arduino maintainer=Arduino sentence=Allows playing audio files from an SD card. For Arduino DUE only. diff --git a/libraries/Audio/src/Audio.cpp b/libraries/Audio/src/Audio.cpp index d502cdd5c..c6bf4ade0 100644 --- a/libraries/Audio/src/Audio.cpp +++ b/libraries/Audio/src/Audio.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 by Cristian Maglie + * Copyright (c) 2012 Arduino LLC. All right reserved. * Audio library for Arduino Due. * * This file is free software; you can redistribute it and/or modify diff --git a/libraries/Audio/src/Audio.h b/libraries/Audio/src/Audio.h index b06342b95..670b03b6e 100644 --- a/libraries/Audio/src/Audio.h +++ b/libraries/Audio/src/Audio.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 by Cristian Maglie + * Copyright (c) 2012 Arduino LLC. All right reserved. * Audio library for Arduino Due. * * This file is free software; you can redistribute it and/or modify diff --git a/libraries/Audio/src/DAC.cpp b/libraries/Audio/src/DAC.cpp index 8c853861f..719031292 100644 --- a/libraries/Audio/src/DAC.cpp +++ b/libraries/Audio/src/DAC.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 by Cristian Maglie + * Copyright (c) 2012 Arduino LLC. All right reserved. * DAC library for Arduino Due. * * This file is free software; you can redistribute it and/or modify diff --git a/libraries/Audio/src/DAC.h b/libraries/Audio/src/DAC.h index af3b8011b..49ec30260 100644 --- a/libraries/Audio/src/DAC.h +++ b/libraries/Audio/src/DAC.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 by Cristian Maglie + * Copyright (c) 2012 Arduino LLC. All right reserved. * DAC library for Arduino Due. * * This file is free software; you can redistribute it and/or modify diff --git a/libraries/Bridge/README.adoc b/libraries/Bridge/README.adoc index 9229d3e18..8b5e970a6 100644 --- a/libraries/Bridge/README.adoc +++ b/libraries/Bridge/README.adoc @@ -7,7 +7,7 @@ http://arduino.cc/en/Reference/YunBridgeLibrary == License == -Copyright (c) Arduino LLC. All right reserved. +Copyright (c) 2014 Arduino LLC. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public diff --git a/libraries/Bridge/examples/TemperatureWebPanel/TemperatureWebPanel.ino b/libraries/Bridge/examples/TemperatureWebPanel/TemperatureWebPanel.ino index 81cf1745e..a695fbdd5 100644 --- a/libraries/Bridge/examples/TemperatureWebPanel/TemperatureWebPanel.ino +++ b/libraries/Bridge/examples/TemperatureWebPanel/TemperatureWebPanel.ino @@ -102,11 +102,11 @@ void loop() { // convert the millivolts to temperature celsius: float temperature = (voltage - 500) / 10; // print the temperature: - client.print("Current time on the Yún: "); + client.print("Current time on the Yún: "); client.println(timeString); client.print("
Current temperature: "); client.print(temperature); - client.print(" degrees C"); + client.print(" °C"); client.print("
This sketch has been running since "); client.print(startString); client.print("
Hits so far: "); diff --git a/libraries/Bridge/keywords.txt b/libraries/Bridge/keywords.txt index 688874779..c96a8ed9c 100644 --- a/libraries/Bridge/keywords.txt +++ b/libraries/Bridge/keywords.txt @@ -3,18 +3,18 @@ ####################################### ####################################### -# Class (KEYWORD3) +# Class (KEYWORD1) ####################################### -Bridge KEYWORD3 -FileIO KEYWORD3 -FileSystem KEYWORD3 -Console KEYWORD3 -Process KEYWORD3 -Mailbox KEYWORD3 -HttpClient KEYWORD3 -YunServer KEYWORD3 -YunClient KEYWORD3 +Bridge KEYWORD1 YunBridgeLibrary +FileIO KEYWORD4 YunFileIOConstructor +FileSystem KEYWORD1 YunFileIOConstructor +Console KEYWORD1 YunConsoleConstructor +Process KEYWORD1 YunProcessConstructor +Mailbox KEYWORD1 YunMailboxConstructor +HttpClient KEYWORD1 YunHttpClientConstructor +YunServer KEYWORD1 YunServerConstructor +YunClient KEYWORD1 YunClientConstructor ####################################### # Methods and Functions (KEYWORD2) diff --git a/libraries/Bridge/library.properties b/libraries/Bridge/library.properties index 11c60e731..dd8eba068 100644 --- a/libraries/Bridge/library.properties +++ b/libraries/Bridge/library.properties @@ -1,5 +1,5 @@ name=Bridge -version=1.0 +version=1.0.4 author=Arduino maintainer=Arduino sentence=Enables the communication between the Linux processor and the AVR. For Arduino Yún and TRE only. diff --git a/libraries/Bridge/src/Bridge.cpp b/libraries/Bridge/src/Bridge.cpp index c772dee8e..4cf74661d 100644 --- a/libraries/Bridge/src/Bridge.cpp +++ b/libraries/Bridge/src/Bridge.cpp @@ -87,10 +87,11 @@ void BridgeClass::begin() { void BridgeClass::put(const char *key, const char *value) { // TODO: do it in a more efficient way String cmd = "D"; + uint8_t res[1]; cmd += key; cmd += "\xFE"; cmd += value; - transfer((uint8_t*)cmd.c_str(), cmd.length()); + transfer((uint8_t*)cmd.c_str(), cmd.length(), res, 1); } unsigned int BridgeClass::get(const char *key, uint8_t *value, unsigned int maxlen) { @@ -191,12 +192,13 @@ uint16_t BridgeClass::transfer(const uint8_t *buff1, uint16_t len1, // Recv data for (uint16_t i = 0; i < l; i++) { + // Cut received data if rxbuffer is too small + if (i >= rxlen) + break; int c = timedRead(5); if (c < 0) continue; - // Cut received data if rxbuffer is too small - if (i < rxlen) - rxbuff[i] = c; + rxbuff[i] = c; crcUpdate(c); } diff --git a/libraries/Bridge/src/Bridge.h b/libraries/Bridge/src/Bridge.h index 954571a62..14f86cbd3 100644 --- a/libraries/Bridge/src/Bridge.h +++ b/libraries/Bridge/src/Bridge.h @@ -19,6 +19,10 @@ #ifndef BRIDGE_H_ #define BRIDGE_H_ +#ifndef BRIDGE_BAUDRATE +#define BRIDGE_BAUDRATE 250000 +#endif + #include #include @@ -96,7 +100,7 @@ class SerialBridgeClass : public BridgeClass { // Empty } - void begin(unsigned long baudrate = 250000) { + void begin(unsigned long baudrate = BRIDGE_BAUDRATE) { serial.begin(baudrate); BridgeClass::begin(); } diff --git a/libraries/Bridge/src/FileIO.cpp b/libraries/Bridge/src/FileIO.cpp index 5f4a2e116..603657239 100644 --- a/libraries/Bridge/src/FileIO.cpp +++ b/libraries/Bridge/src/FileIO.cpp @@ -175,7 +175,8 @@ void File::close() { if (mode == 255) return; uint8_t cmd[] = {'f', handle}; - bridge.transfer(cmd, 2); + uint8_t ret[1]; + bridge.transfer(cmd, 2, ret, 1); mode = 255; } diff --git a/libraries/Esplora/README.adoc b/libraries/Esplora/README.adoc index a8b2288cf..1f71b38ed 100644 --- a/libraries/Esplora/README.adoc +++ b/libraries/Esplora/README.adoc @@ -7,7 +7,7 @@ http://arduino.cc/en/Reference/EsploraLibrary == License == -Copyright (c) Arduino LLC. All right reserved. +Copyright (c) 2012 Arduino LLC. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public diff --git a/libraries/Esplora/keywords.txt b/libraries/Esplora/keywords.txt index 18d394b31..afd5ecd1b 100644 --- a/libraries/Esplora/keywords.txt +++ b/libraries/Esplora/keywords.txt @@ -4,7 +4,7 @@ # Class ####################################### -Esplora KEYWORD3 +Esplora KEYWORD1 EsploraLibrary ####################################### # Methods and Functions diff --git a/libraries/Esplora/library.properties b/libraries/Esplora/library.properties index d0e155088..f54617f12 100644 --- a/libraries/Esplora/library.properties +++ b/libraries/Esplora/library.properties @@ -1,9 +1,9 @@ -name=Esplora -version=1.0 -author=Arduino -maintainer=Arduino -sentence=Grants easy access to the various sensors and actuators of the Esplora. For Arduino Esplora only. -paragraph=The sensors available on the board are:2-Axis analog joystick with center push-button,4 push-buttons,microphone, light sensor, temperature sensor, 3-axis accelerometer, 2 TinkerKit input connectors.
The actuators available on the board are: bright RGB LED, piezo buzzer, 2 TinkerKit output connectors. -category=Device Control -url=http://arduino.cc/en/Reference/EsploraLibrary -architectures=avr +name=Esplora +version=1.0.3 +author=Arduino +maintainer=Arduino +sentence=Grants easy access to the various sensors and actuators of the Esplora. For Arduino Esplora only. +paragraph=The sensors available on the board are:2-Axis analog joystick with center push-button,4 push-buttons,microphone, light sensor, temperature sensor, 3-axis accelerometer, 2 TinkerKit input connectors.
The actuators available on the board are: bright RGB LED, piezo buzzer, 2 TinkerKit output connectors. +category=Device Control +url=http://arduino.cc/en/Reference/EsploraLibrary +architectures=avr diff --git a/libraries/Esplora/src/Esplora.cpp b/libraries/Esplora/src/Esplora.cpp index 29c9e191a..a80894446 100644 --- a/libraries/Esplora/src/Esplora.cpp +++ b/libraries/Esplora/src/Esplora.cpp @@ -1,7 +1,7 @@ /* Esplora.cpp - Arduino Esplora board library Written by Enrico Gueli - Copyright (c) 2012 Arduino(TM) All right reserved. + Copyright (c) 2012 Arduino LLC. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -44,10 +44,10 @@ const byte GREEN_PIN = 10; const byte BUZZER_PIN = 6; // non-multiplexer Esplora pins: -// Accelerometer: x-A5, y-A7, z-A6 +// Accelerometer: x-A5, y-A11, z-A6 // External outputs: D3, D11 -// Buzzer: A8 -// RGB Led: red-D5, green-D10/A11, blue-D9/A10 +// Buzzer: D6 +// RGB Led: red-D5, green-D10, blue-D9 // Led 13: D13 const byte ACCEL_X_PIN = A5; diff --git a/libraries/Esplora/src/Esplora.h b/libraries/Esplora/src/Esplora.h index 56f76ab3a..4e59fbe08 100644 --- a/libraries/Esplora/src/Esplora.h +++ b/libraries/Esplora/src/Esplora.h @@ -1,7 +1,7 @@ /* Esplora.h - Arduino Esplora board library Written by Enrico Gueli - Copyright (c) 2012 Arduino(TM) All right reserved. + Copyright (c) 2012 Arduino LLC. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public diff --git a/libraries/Ethernet/README.adoc b/libraries/Ethernet/README.adoc index c1772ae5d..c01060742 100644 --- a/libraries/Ethernet/README.adoc +++ b/libraries/Ethernet/README.adoc @@ -7,7 +7,7 @@ http://arduino.cc/en/Reference/Ethernet == License == -Copyright (c) Arduino LLC. All right reserved. +Copyright (c) 2010 Arduino LLC. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public diff --git a/libraries/Ethernet/keywords.txt b/libraries/Ethernet/keywords.txt index 6b37cbe05..7b162a54b 100644 --- a/libraries/Ethernet/keywords.txt +++ b/libraries/Ethernet/keywords.txt @@ -6,10 +6,10 @@ # Datatypes (KEYWORD1) ####################################### -Ethernet KEYWORD1 -EthernetClient KEYWORD1 -EthernetServer KEYWORD1 -IPAddress KEYWORD1 +Ethernet KEYWORD1 Ethernet +EthernetClient KEYWORD1 EthernetClient +EthernetServer KEYWORD1 EthernetServer +IPAddress KEYWORD1 EthernetIPAddress ####################################### # Methods and Functions (KEYWORD2) diff --git a/libraries/Ethernet/library.properties b/libraries/Ethernet/library.properties index b82197218..1634bfea7 100644 --- a/libraries/Ethernet/library.properties +++ b/libraries/Ethernet/library.properties @@ -1,9 +1,9 @@ -name=Ethernet -version=1.0 -author=Arduino -maintainer=Arduino -sentence=Enables network connection (local and Internet) using the Arduino Ethernet board or shield. For all Arduino boards. -paragraph=With this library you can use the Arduino Ethernet (shield or board) to connect to Internet. The library provides both Client and server functionalities. The library permits you to connect to a local network also with DHCP and to resolve DNS. -category=Communication -url=http://arduino.cc/en/Reference/Ethernet -architectures=* +name=Ethernet +version=1.0.2 +author=Arduino +maintainer=Arduino +sentence=Enables network connection (local and Internet) using the Arduino Ethernet board or shield. For all Arduino boards. +paragraph=With this library you can use the Arduino Ethernet (shield or board) to connect to Internet. The library provides both Client and server functionalities. The library permits you to connect to a local network also with DHCP and to resolve DNS. +category=Communication +url=http://arduino.cc/en/Reference/Ethernet +architectures=* diff --git a/libraries/Ethernet/src/utility/socket.cpp b/libraries/Ethernet/src/utility/socket.cpp index 4ed4317ea..9254b7439 100644 --- a/libraries/Ethernet/src/utility/socket.cpp +++ b/libraries/Ethernet/src/utility/socket.cpp @@ -1,5 +1,5 @@ -#include "utility/w5100.h" -#include "utility/socket.h" +#include "w5100.h" +#include "socket.h" static uint16_t local_port; diff --git a/libraries/Ethernet/src/utility/w5100.cpp b/libraries/Ethernet/src/utility/w5100.cpp index d4b73bfc7..d0a9bb229 100644 --- a/libraries/Ethernet/src/utility/w5100.cpp +++ b/libraries/Ethernet/src/utility/w5100.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 by Cristian Maglie + * Copyright (c) 2010 by Arduino LLC. All rights reserved. * * This file is free software; you can redistribute it and/or modify * it under the terms of either the GNU General Public License version 2 @@ -10,7 +10,7 @@ #include #include -#include "utility/w5100.h" +#include "w5100.h" // W5100 controller instance W5100Class W5100; diff --git a/libraries/Ethernet/src/utility/w5100.h b/libraries/Ethernet/src/utility/w5100.h index c8f22b9b9..fd9ea35ec 100644 --- a/libraries/Ethernet/src/utility/w5100.h +++ b/libraries/Ethernet/src/utility/w5100.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 by Cristian Maglie + * Copyright (c) 2010 by Arduino LLC. All rights reserved. * * This file is free software; you can redistribute it and/or modify * it under the terms of either the GNU General Public License version 2 diff --git a/libraries/Firmata/README.adoc b/libraries/Firmata/README.adoc index d217c9752..a85d48540 100644 --- a/libraries/Firmata/README.adoc +++ b/libraries/Firmata/README.adoc @@ -7,7 +7,8 @@ http://arduino.cc/en/Reference/Firmata == License == -Copyright (c) Arduino LLC. All right reserved. +Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. +Copyright (c) 2010 Arduino LLC. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public diff --git a/libraries/Firmata/keywords.txt b/libraries/Firmata/keywords.txt index 52e0a9c74..ca4522c3d 100644 --- a/libraries/Firmata/keywords.txt +++ b/libraries/Firmata/keywords.txt @@ -6,7 +6,7 @@ # Datatypes (KEYWORD1) ####################################### -Firmata KEYWORD1 +Firmata KEYWORD1 Firmata callbackFunction KEYWORD1 systemResetCallbackFunction KEYWORD1 stringCallbackFunction KEYWORD1 diff --git a/libraries/Firmata/library.properties b/libraries/Firmata/library.properties index 426a086ba..4b508d57c 100644 --- a/libraries/Firmata/library.properties +++ b/libraries/Firmata/library.properties @@ -1,9 +1,9 @@ -name=Firmata -version=2.3.6 -author=Firmata Developers -maintainer=Firmata Developers -sentence=Enables the communication with computer apps using a standard serial protocol. For all Arduino boards. -paragraph=The Firmata library implements the Firmata protocol for communicating with software on the host computer. This allows you to write custom firmware without having to create your own protocol and objects for the programming environment that you are using. -category=Device Control -url=http://firmata.org -architectures=* +name=Firmata +version=2.3.8 +author=Firmata Developers +maintainer=Firmata Developers +sentence=Enables the communication with computer apps using a standard serial protocol. For all Arduino boards. +paragraph=The Firmata library implements the Firmata protocol for communicating with software on the host computer. This allows you to write custom firmware without having to create your own protocol and objects for the programming environment that you are using. +category=Device Control +url=http://firmata.org +architectures=* diff --git a/libraries/Firmata/src/Firmata.h b/libraries/Firmata/src/Firmata.h index 225dd78b7..1a7636ac4 100644 --- a/libraries/Firmata/src/Firmata.h +++ b/libraries/Firmata/src/Firmata.h @@ -1,6 +1,6 @@ /* Firmata.h - Firmata library - Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights reserved. + Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public diff --git a/libraries/GSM/README.adoc b/libraries/GSM/README.adoc index 1b264199c..8c59e965b 100644 --- a/libraries/GSM/README.adoc +++ b/libraries/GSM/README.adoc @@ -6,8 +6,7 @@ For more information about this library please visit us at http://arduino.cc/en/Reference/GSM == License == - -Copyright (c) Arduino LLC. All right reserved. +Copyright (c) 2012 Telefónica Digital - PDI - Physical Internet Lab This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public diff --git a/libraries/GSM/extras/License.txt b/libraries/GSM/extras/License.txt index fb6d90b9f..4114b2b23 100644 --- a/libraries/GSM/extras/License.txt +++ b/libraries/GSM/extras/License.txt @@ -1,166 +1,142 @@ GNU LESSER GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. +Version 2.1, February 1999 +Copyright (C) 1991, 1999 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. - This version of the GNU Lesser General Public License incorporates -the terms and conditions of version 3 of the GNU General Public -License, supplemented by the additional permissions listed below. +[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.] - 0. Additional Definitions. +Preamble - As used herein, "this License" refers to version 3 of the GNU Lesser -General Public License, and the "GNU GPL" refers to version 3 of the GNU -General Public License. +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. - "The Library" refers to a covered work governed by this License, -other than an Application or a Combined Work as defined below. +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. - An "Application" is any work that makes use of an interface provided -by the Library, but which is not otherwise based on the Library. -Defining a subclass of a class defined by the Library is deemed a mode -of using an interface provided by the Library. +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. - A "Combined Work" is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the "Linked -Version". +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. - The "Minimal Corresponding Source" for a Combined Work means the -Corresponding Source for the Combined Work, excluding any source code -for portions of the Combined Work that, considered in isolation, are -based on the Application, and not on the Linked Version. +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. - The "Corresponding Application Code" for a Combined Work means the -object code and/or source code for the Application, including any data -and utility programs needed for reproducing the Combined Work from the -Application, but excluding the System Libraries of the Combined Work. +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. - 1. Exception to Section 3 of the GNU GPL. +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. - You may convey a covered work under sections 3 and 4 of this License -without being bound by section 3 of the GNU GPL. +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. - 2. Conveying Modified Versions. +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. - If you modify a copy of the Library, and, in your modifications, a -facility refers to a function or data to be supplied by an Application -that uses the facility (other than as an argument passed when the -facility is invoked), then you may convey a copy of the modified -version: +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. - a) under this License, provided that you make a good faith effort to - ensure that, in the event an Application does not supply the - function or data, the facility still operates, and performs - whatever part of its purpose remains meaningful, or +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. - b) under the GNU GPL, with none of the additional permissions of - this License applicable to that copy. +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. - 3. Object Code Incorporating Material from Library Header Files. +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. - The object code form of an Application may incorporate material from -a header file that is part of the Library. You may convey such object -code under terms of your choice, provided that, if the incorporated -material is not limited to numerical parameters, data structure -layouts and accessors, or small macros, inline functions and templates -(ten or fewer lines in length), you do both of the following: +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. - a) Give prominent notice with each copy of the object code that the - Library is used in it and that the Library and its use are - covered by this License. +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. +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - b) Accompany the object code with a copy of the GNU GPL and this license - document. +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". - 4. Combined Works. +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. - You may convey a Combined Work under terms of your choice that, -taken together, effectively do not restrict modification of the -portions of the Library contained in the Combined Work and reverse -engineering for debugging such modifications, if you also do each of -the following: +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".) - a) Give prominent notice with each copy of the Combined Work that - the Library is used in it and that the Library and its use are - covered by this License. +"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. - b) Accompany the Combined Work with a copy of the GNU GPL and this license - document. +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. - c) For a Combined Work that displays copyright notices during - execution, include the copyright notice for the Library among - these notices, as well as a reference directing the user to the - copies of the GNU GPL and this license document. +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. - d) Do one of the following: +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. - 0) Convey the Minimal Corresponding Source under the terms of this - License, and the Corresponding Application Code in a form - suitable for, and under terms that permit, the user to - recombine or relink the Application with a modified version of - the Linked Version to produce a modified Combined Work, in the - manner specified by section 6 of the GNU GPL for conveying - Corresponding Source. +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: - 1) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (a) uses at run time - a copy of the Library already present on the user's computer - system, and (b) will operate properly with a modified version - of the Library that is interface-compatible with the Linked - Version. + 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. - e) Provide Installation Information, but only if you would otherwise - be required to provide such information under section 6 of the - GNU GPL, and only to the extent that such information is - necessary to install and execute a modified version of the - Combined Work produced by recombining or relinking the - Application with a modified version of the Linked Version. (If - you use option 4d0, the Installation Information must accompany - the Minimal Corresponding Source and Corresponding Application - Code. If you use option 4d1, you must provide the Installation - Information in the manner specified by section 6 of the GNU GPL - for conveying Corresponding Source.) + (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.) - 5. Combined Libraries. +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. - 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 that are not Applications and are not covered by this -License, and convey such a combined library under terms of your -choice, if you do both of the following: +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. - a) Accompany the combined library with a copy of the same work based - on the Library, uncombined with any other library facilities, - conveyed under the terms of this License. +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. - b) Give prominent notice with the combined library that part of it - is a work based on the Library, and explaining where to find the - accompanying uncombined form of the same work. +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. - 6. Revised Versions of the GNU Lesser General Public License. +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. - The Free Software Foundation may publish revised and/or new versions -of the GNU 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. +This option is useful when you wish to copy part of the code of the Library into a program that is not a library. - Each version is given a distinguishing version number. If the -Library as you received it specifies that a certain numbered version -of the GNU Lesser General Public License "or any later version" -applies to it, you have the option of following the terms and -conditions either of that published version or of any later version -published by the Free Software Foundation. If the Library as you -received it does not specify a version number of the GNU Lesser -General Public License, you may choose any version of the GNU Lesser -General Public License ever published by the Free Software Foundation. +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 the Library as you received it specifies that a proxy can decide -whether future versions of the GNU Lesser General Public License shall -apply, that proxy's public statement of acceptance of any version is -permanent authorization for you to choose that version for the -Library. +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 diff --git a/libraries/GSM/keywords.txt b/libraries/GSM/keywords.txt index 0662e75bd..4a44464ad 100644 --- a/libraries/GSM/keywords.txt +++ b/libraries/GSM/keywords.txt @@ -4,16 +4,16 @@ # Class ####################################### -GSM KEYWORD3 -GSMVoiceCall KEYWORD3 -GSM_SMS KEYWORD3 -GPRS KEYWORD3 -GSMClient KEYWORD3 -GSMServer KEYWORD3 -GSMModem KEYWORD3 -GSMScanner KEYWORD3 -GSMPIN KEYWORD3 -GSMBand KEYWORD3 +GSM KEYWORD1 GSM +GSMVoiceCall KEYWORD1 GSMVCSConstructor +GSM_SMS KEYWORD1 GSMSMSConstructor +GPRS KEYWORD1 GPRSConstructor +GSMClient KEYWORD1 GSMClientConstructor +GSMServer KEYWORD1 GSMServerConstructor +GSMModem KEYWORD1 GSMModemConstructor +GSMScanner KEYWORD1 GSMScannerConstructor +GSMPIN KEYWORD1 GSMPINConstructor +GSMBand KEYWORD1 GSMBandConstructor ####################################### # Methods and Functions @@ -69,4 +69,4 @@ GSM_MODE_DCS LITERAL1 GSM_MODE_PCS LITERAL1 GSM_MODE_EGSM_DCS LITERAL1 GSM_MODE_GSM850_PCS LITERAL1 -GSM_MODE_GSM850_EGSM_DCS_PCS LITERAL1 \ No newline at end of file +GSM_MODE_GSM850_EGSM_DCS_PCS LITERAL1 diff --git a/libraries/GSM/library.properties b/libraries/GSM/library.properties index 768ebeffc..8c81c5d7f 100644 --- a/libraries/GSM/library.properties +++ b/libraries/GSM/library.properties @@ -1,5 +1,5 @@ name=GSM -version=1.0 +version=1.0.3 author=Arduino maintainer=Arduino sentence=Enables GSM/GRPS network connection using the Arduino GSM Shield. For all Arduino boards BUT Arduino DUE. diff --git a/libraries/GSM/src/GSM3IO.h b/libraries/GSM/src/GSM3IO.h index 502b55237..da1e78476 100644 --- a/libraries/GSM/src/GSM3IO.h +++ b/libraries/GSM/src/GSM3IO.h @@ -1,3 +1,36 @@ +/* +This file is part of the GSM3 communications library for Arduino +-- Multi-transport communications platform +-- Fully asynchronous +-- Includes code for the Arduino-Telefonica GSM/GPRS Shield V1 +-- Voice calls +-- SMS +-- TCP/IP connections +-- HTTP basic clients + +This library has been developed by Telefónica Digital - PDI - +- Physical Internet Lab, as part as its collaboration with +Arduino and the Open Hardware Community. + +September-December 2012 + +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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +The latest version of this library can always be found at +https://github.com/BlueVia/Official-Arduino +*/ #ifdef TTOPEN_V1 #define __POWERPIN__ 5 #define __RESETPIN__ 6 @@ -23,4 +56,4 @@ #define __TXPIN__ 3 #define __RXPIN__ 8 #define __RXINT__ 3 -#endif \ No newline at end of file +#endif diff --git a/libraries/GSM/src/GSM3MobileAccessProvider.cpp b/libraries/GSM/src/GSM3MobileAccessProvider.cpp index 02d108081..225069b2b 100644 --- a/libraries/GSM/src/GSM3MobileAccessProvider.cpp +++ b/libraries/GSM/src/GSM3MobileAccessProvider.cpp @@ -1,3 +1,36 @@ +/* +This file is part of the GSM3 communications library for Arduino +-- Multi-transport communications platform +-- Fully asynchronous +-- Includes code for the Arduino-Telefonica GSM/GPRS Shield V1 +-- Voice calls +-- SMS +-- TCP/IP connections +-- HTTP basic clients + +This library has been developed by Telefónica Digital - PDI - +- Physical Internet Lab, as part as its collaboration with +Arduino and the Open Hardware Community. + +September-December 2012 + +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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +The latest version of this library can always be found at +https://github.com/BlueVia/Official-Arduino +*/ #include -GSM3MobileAccessProvider* theGSM3MobileAccessProvider; \ No newline at end of file +GSM3MobileAccessProvider* theGSM3MobileAccessProvider; diff --git a/libraries/GSM/src/GSM3MobileCellManagement.cpp b/libraries/GSM/src/GSM3MobileCellManagement.cpp index 1db20b94a..5db2717f8 100644 --- a/libraries/GSM/src/GSM3MobileCellManagement.cpp +++ b/libraries/GSM/src/GSM3MobileCellManagement.cpp @@ -1 +1,34 @@ -#include \ No newline at end of file +/* +This file is part of the GSM3 communications library for Arduino +-- Multi-transport communications platform +-- Fully asynchronous +-- Includes code for the Arduino-Telefonica GSM/GPRS Shield V1 +-- Voice calls +-- SMS +-- TCP/IP connections +-- HTTP basic clients + +This library has been developed by Telefónica Digital - PDI - +- Physical Internet Lab, as part as its collaboration with +Arduino and the Open Hardware Community. + +September-December 2012 + +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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +The latest version of this library can always be found at +https://github.com/BlueVia/Official-Arduino +*/ +#include diff --git a/libraries/GSM/src/GSM3MobileClientProvider.cpp b/libraries/GSM/src/GSM3MobileClientProvider.cpp index 3636a75d2..0de3ceea7 100644 --- a/libraries/GSM/src/GSM3MobileClientProvider.cpp +++ b/libraries/GSM/src/GSM3MobileClientProvider.cpp @@ -1,3 +1,36 @@ +/* +This file is part of the GSM3 communications library for Arduino +-- Multi-transport communications platform +-- Fully asynchronous +-- Includes code for the Arduino-Telefonica GSM/GPRS Shield V1 +-- Voice calls +-- SMS +-- TCP/IP connections +-- HTTP basic clients + +This library has been developed by Telefónica Digital - PDI - +- Physical Internet Lab, as part as its collaboration with +Arduino and the Open Hardware Community. + +September-December 2012 + +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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +The latest version of this library can always be found at +https://github.com/BlueVia/Official-Arduino +*/ #include -GSM3MobileClientProvider* theGSM3MobileClientProvider; \ No newline at end of file +GSM3MobileClientProvider* theGSM3MobileClientProvider; diff --git a/libraries/GSM/src/GSM3MobileDataNetworkProvider.cpp b/libraries/GSM/src/GSM3MobileDataNetworkProvider.cpp index 538f6d439..c57c34168 100644 --- a/libraries/GSM/src/GSM3MobileDataNetworkProvider.cpp +++ b/libraries/GSM/src/GSM3MobileDataNetworkProvider.cpp @@ -1,3 +1,36 @@ +/* +This file is part of the GSM3 communications library for Arduino +-- Multi-transport communications platform +-- Fully asynchronous +-- Includes code for the Arduino-Telefonica GSM/GPRS Shield V1 +-- Voice calls +-- SMS +-- TCP/IP connections +-- HTTP basic clients + +This library has been developed by Telefónica Digital - PDI - +- Physical Internet Lab, as part as its collaboration with +Arduino and the Open Hardware Community. + +September-December 2012 + +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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +The latest version of this library can always be found at +https://github.com/BlueVia/Official-Arduino +*/ #include -// GSM3MobileDataNetworkProvider* theGSM3MobileDataNetworkProvider; \ No newline at end of file +// GSM3MobileDataNetworkProvider* theGSM3MobileDataNetworkProvider; diff --git a/libraries/GSM/src/GSM3MobileSMSProvider.cpp b/libraries/GSM/src/GSM3MobileSMSProvider.cpp index b53633083..e5575ceb8 100644 --- a/libraries/GSM/src/GSM3MobileSMSProvider.cpp +++ b/libraries/GSM/src/GSM3MobileSMSProvider.cpp @@ -1,3 +1,36 @@ +/* +This file is part of the GSM3 communications library for Arduino +-- Multi-transport communications platform +-- Fully asynchronous +-- Includes code for the Arduino-Telefonica GSM/GPRS Shield V1 +-- Voice calls +-- SMS +-- TCP/IP connections +-- HTTP basic clients + +This library has been developed by Telefónica Digital - PDI - +- Physical Internet Lab, as part as its collaboration with +Arduino and the Open Hardware Community. + +September-December 2012 + +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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +The latest version of this library can always be found at +https://github.com/BlueVia/Official-Arduino +*/ #include GSM3MobileSMSProvider* theGSM3SMSProvider; diff --git a/libraries/GSM/src/GSM3MobileServerProvider.cpp b/libraries/GSM/src/GSM3MobileServerProvider.cpp index 4739ac7e1..d101bbab2 100644 --- a/libraries/GSM/src/GSM3MobileServerProvider.cpp +++ b/libraries/GSM/src/GSM3MobileServerProvider.cpp @@ -1,5 +1,39 @@ - #include +/* +This file is part of the GSM3 communications library for Arduino +-- Multi-transport communications platform +-- Fully asynchronous +-- Includes code for the Arduino-Telefonica GSM/GPRS Shield V1 +-- Voice calls +-- SMS +-- TCP/IP connections +-- HTTP basic clients + +This library has been developed by Telefónica Digital - PDI - +- Physical Internet Lab, as part as its collaboration with +Arduino and the Open Hardware Community. + +September-December 2012 + +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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +The latest version of this library can always be found at +https://github.com/BlueVia/Official-Arduino +*/ + +#include + +GSM3MobileServerProvider* theGSM3MobileServerProvider; - GSM3MobileServerProvider* theGSM3MobileServerProvider; - \ No newline at end of file diff --git a/libraries/GSM/src/GSM3MobileVoiceProvider.cpp b/libraries/GSM/src/GSM3MobileVoiceProvider.cpp index 7af4e8fc7..b74cbfba7 100644 --- a/libraries/GSM/src/GSM3MobileVoiceProvider.cpp +++ b/libraries/GSM/src/GSM3MobileVoiceProvider.cpp @@ -1,4 +1,36 @@ +/* +This file is part of the GSM3 communications library for Arduino +-- Multi-transport communications platform +-- Fully asynchronous +-- Includes code for the Arduino-Telefonica GSM/GPRS Shield V1 +-- Voice calls +-- SMS +-- TCP/IP connections +-- HTTP basic clients + +This library has been developed by Telefónica Digital - PDI - +- Physical Internet Lab, as part as its collaboration with +Arduino and the Open Hardware Community. + +September-December 2012 + +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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +The latest version of this library can always be found at +https://github.com/BlueVia/Official-Arduino +*/ #include - GSM3MobileVoiceProvider* theGSM3MobileVoiceProvider; diff --git a/libraries/GSM/src/GSM3ShieldV1AccessProvider.cpp b/libraries/GSM/src/GSM3ShieldV1AccessProvider.cpp index 330d3f835..19f9768bc 100644 --- a/libraries/GSM/src/GSM3ShieldV1AccessProvider.cpp +++ b/libraries/GSM/src/GSM3ShieldV1AccessProvider.cpp @@ -1,3 +1,36 @@ +/* +This file is part of the GSM3 communications library for Arduino +-- Multi-transport communications platform +-- Fully asynchronous +-- Includes code for the Arduino-Telefonica GSM/GPRS Shield V1 +-- Voice calls +-- SMS +-- TCP/IP connections +-- HTTP basic clients + +This library has been developed by Telefónica Digital - PDI - +- Physical Internet Lab, as part as its collaboration with +Arduino and the Open Hardware Community. + +September-December 2012 + +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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +The latest version of this library can always be found at +https://github.com/BlueVia/Official-Arduino +*/ #include #include #include "GSM3IO.h" @@ -320,4 +353,4 @@ bool GSM3ShieldV1AccessProvider::secureShutdown() #endif return true; -} \ No newline at end of file +} diff --git a/libraries/GSM/src/GSM3ShieldV1BandManagement.cpp b/libraries/GSM/src/GSM3ShieldV1BandManagement.cpp index 94dec9aea..48132dfb1 100644 --- a/libraries/GSM/src/GSM3ShieldV1BandManagement.cpp +++ b/libraries/GSM/src/GSM3ShieldV1BandManagement.cpp @@ -1,3 +1,36 @@ +/* +This file is part of the GSM3 communications library for Arduino +-- Multi-transport communications platform +-- Fully asynchronous +-- Includes code for the Arduino-Telefonica GSM/GPRS Shield V1 +-- Voice calls +-- SMS +-- TCP/IP connections +-- HTTP basic clients + +This library has been developed by Telefónica Digital - PDI - +- Physical Internet Lab, as part as its collaboration with +Arduino and the Open Hardware Community. + +September-December 2012 + +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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +The latest version of this library can always be found at +https://github.com/BlueVia/Official-Arduino +*/ #include GSM3ShieldV1BandManagement::GSM3ShieldV1BandManagement(bool trace): modem(trace) @@ -64,4 +97,4 @@ bool GSM3ShieldV1BandManagement::setBand(String band) return true; else return false; -} \ No newline at end of file +} diff --git a/libraries/GSM/src/GSM3ShieldV1BaseProvider.cpp b/libraries/GSM/src/GSM3ShieldV1BaseProvider.cpp index 9d4970d03..435a077c5 100644 --- a/libraries/GSM/src/GSM3ShieldV1BaseProvider.cpp +++ b/libraries/GSM/src/GSM3ShieldV1BaseProvider.cpp @@ -1,3 +1,36 @@ +/* +This file is part of the GSM3 communications library for Arduino +-- Multi-transport communications platform +-- Fully asynchronous +-- Includes code for the Arduino-Telefonica GSM/GPRS Shield V1 +-- Voice calls +-- SMS +-- TCP/IP connections +-- HTTP basic clients + +This library has been developed by Telefónica Digital - PDI - +- Physical Internet Lab, as part as its collaboration with +Arduino and the Open Hardware Community. + +September-December 2012 + +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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +The latest version of this library can always be found at +https://github.com/BlueVia/Official-Arduino +*/ #include #include #include diff --git a/libraries/GSM/src/GSM3ShieldV1CellManagement.cpp b/libraries/GSM/src/GSM3ShieldV1CellManagement.cpp index 2af91abff..4c6922404 100644 --- a/libraries/GSM/src/GSM3ShieldV1CellManagement.cpp +++ b/libraries/GSM/src/GSM3ShieldV1CellManagement.cpp @@ -1,3 +1,36 @@ +/* +This file is part of the GSM3 communications library for Arduino +-- Multi-transport communications platform +-- Fully asynchronous +-- Includes code for the Arduino-Telefonica GSM/GPRS Shield V1 +-- Voice calls +-- SMS +-- TCP/IP connections +-- HTTP basic clients + +This library has been developed by Telefónica Digital - PDI - +- Physical Internet Lab, as part as its collaboration with +Arduino and the Open Hardware Community. + +September-December 2012 + +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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +The latest version of this library can always be found at +https://github.com/BlueVia/Official-Arduino +*/ #include GSM3ShieldV1CellManagement::GSM3ShieldV1CellManagement() @@ -165,4 +198,4 @@ void GSM3ShieldV1CellManagement::manageResponse(byte from, byte to) getICCIDContinue(); break; } -} \ No newline at end of file +} diff --git a/libraries/GSM/src/GSM3ShieldV1ClientProvider.cpp b/libraries/GSM/src/GSM3ShieldV1ClientProvider.cpp index 92d3e8577..6540ef1b2 100644 --- a/libraries/GSM/src/GSM3ShieldV1ClientProvider.cpp +++ b/libraries/GSM/src/GSM3ShieldV1ClientProvider.cpp @@ -1,3 +1,36 @@ +/* +This file is part of the GSM3 communications library for Arduino +-- Multi-transport communications platform +-- Fully asynchronous +-- Includes code for the Arduino-Telefonica GSM/GPRS Shield V1 +-- Voice calls +-- SMS +-- TCP/IP connections +-- HTTP basic clients + +This library has been developed by Telefónica Digital - PDI - +- Physical Internet Lab, as part as its collaboration with +Arduino and the Open Hardware Community. + +September-December 2012 + +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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +The latest version of this library can always be found at +https://github.com/BlueVia/Official-Arduino +*/ #include #include diff --git a/libraries/GSM/src/GSM3ShieldV1DataNetworkProvider.cpp b/libraries/GSM/src/GSM3ShieldV1DataNetworkProvider.cpp index 5f10df76c..467136a52 100644 --- a/libraries/GSM/src/GSM3ShieldV1DataNetworkProvider.cpp +++ b/libraries/GSM/src/GSM3ShieldV1DataNetworkProvider.cpp @@ -1,3 +1,36 @@ +/* +This file is part of the GSM3 communications library for Arduino +-- Multi-transport communications platform +-- Fully asynchronous +-- Includes code for the Arduino-Telefonica GSM/GPRS Shield V1 +-- Voice calls +-- SMS +-- TCP/IP connections +-- HTTP basic clients + +This library has been developed by Telefónica Digital - PDI - +- Physical Internet Lab, as part as its collaboration with +Arduino and the Open Hardware Community. + +September-December 2012 + +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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +The latest version of this library can always be found at +https://github.com/BlueVia/Official-Arduino +*/ #include #include diff --git a/libraries/GSM/src/GSM3ShieldV1ModemCore.cpp b/libraries/GSM/src/GSM3ShieldV1ModemCore.cpp index 20678feeb..234874cd5 100644 --- a/libraries/GSM/src/GSM3ShieldV1ModemCore.cpp +++ b/libraries/GSM/src/GSM3ShieldV1ModemCore.cpp @@ -1,3 +1,36 @@ +/* +This file is part of the GSM3 communications library for Arduino +-- Multi-transport communications platform +-- Fully asynchronous +-- Includes code for the Arduino-Telefonica GSM/GPRS Shield V1 +-- Voice calls +-- SMS +-- TCP/IP connections +-- HTTP basic clients + +This library has been developed by Telefónica Digital - PDI - +- Physical Internet Lab, as part as its collaboration with +Arduino and the Open Hardware Community. + +September-December 2012 + +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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +The latest version of this library can always be found at +https://github.com/BlueVia/Official-Arduino +*/ #include #include diff --git a/libraries/GSM/src/GSM3ShieldV1MultiClientProvider.cpp b/libraries/GSM/src/GSM3ShieldV1MultiClientProvider.cpp index c2fd72d46..b3bdfba84 100644 --- a/libraries/GSM/src/GSM3ShieldV1MultiClientProvider.cpp +++ b/libraries/GSM/src/GSM3ShieldV1MultiClientProvider.cpp @@ -1,3 +1,36 @@ +/* +This file is part of the GSM3 communications library for Arduino +-- Multi-transport communications platform +-- Fully asynchronous +-- Includes code for the Arduino-Telefonica GSM/GPRS Shield V1 +-- Voice calls +-- SMS +-- TCP/IP connections +-- HTTP basic clients + +This library has been developed by Telefónica Digital - PDI - +- Physical Internet Lab, as part as its collaboration with +Arduino and the Open Hardware Community. + +September-December 2012 + +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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +The latest version of this library can always be found at +https://github.com/BlueVia/Official-Arduino +*/ #include #include diff --git a/libraries/GSM/src/GSM3ShieldV1MultiServerProvider.cpp b/libraries/GSM/src/GSM3ShieldV1MultiServerProvider.cpp index de74b4973..6ab37dbad 100644 --- a/libraries/GSM/src/GSM3ShieldV1MultiServerProvider.cpp +++ b/libraries/GSM/src/GSM3ShieldV1MultiServerProvider.cpp @@ -1,3 +1,36 @@ +/* +This file is part of the GSM3 communications library for Arduino +-- Multi-transport communications platform +-- Fully asynchronous +-- Includes code for the Arduino-Telefonica GSM/GPRS Shield V1 +-- Voice calls +-- SMS +-- TCP/IP connections +-- HTTP basic clients + +This library has been developed by Telefónica Digital - PDI - +- Physical Internet Lab, as part as its collaboration with +Arduino and the Open Hardware Community. + +September-December 2012 + +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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +The latest version of this library can always be found at +https://github.com/BlueVia/Official-Arduino +*/ #include #include #include diff --git a/libraries/GSM/src/GSM3ShieldV1SMSProvider.cpp b/libraries/GSM/src/GSM3ShieldV1SMSProvider.cpp index 85d999067..6c028f655 100644 --- a/libraries/GSM/src/GSM3ShieldV1SMSProvider.cpp +++ b/libraries/GSM/src/GSM3ShieldV1SMSProvider.cpp @@ -1,3 +1,36 @@ +/* +This file is part of the GSM3 communications library for Arduino +-- Multi-transport communications platform +-- Fully asynchronous +-- Includes code for the Arduino-Telefonica GSM/GPRS Shield V1 +-- Voice calls +-- SMS +-- TCP/IP connections +-- HTTP basic clients + +This library has been developed by Telefónica Digital - PDI - +- Physical Internet Lab, as part as its collaboration with +Arduino and the Open Hardware Community. + +September-December 2012 + +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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +The latest version of this library can always be found at +https://github.com/BlueVia/Official-Arduino +*/ #include #include diff --git a/libraries/GSM/src/GSM3ShieldV1ServerProvider.cpp b/libraries/GSM/src/GSM3ShieldV1ServerProvider.cpp index 77f543674..61b5c062c 100644 --- a/libraries/GSM/src/GSM3ShieldV1ServerProvider.cpp +++ b/libraries/GSM/src/GSM3ShieldV1ServerProvider.cpp @@ -1,3 +1,36 @@ +/* +This file is part of the GSM3 communications library for Arduino +-- Multi-transport communications platform +-- Fully asynchronous +-- Includes code for the Arduino-Telefonica GSM/GPRS Shield V1 +-- Voice calls +-- SMS +-- TCP/IP connections +-- HTTP basic clients + +This library has been developed by Telefónica Digital - PDI - +- Physical Internet Lab, as part as its collaboration with +Arduino and the Open Hardware Community. + +September-December 2012 + +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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +The latest version of this library can always be found at +https://github.com/BlueVia/Official-Arduino +*/ #include #include #include @@ -202,4 +235,4 @@ void GSM3ShieldV1ServerProvider::releaseSocket(int socket) int GSM3ShieldV1ServerProvider::getNewOccupiedSocketAsServer() { return 0; -} \ No newline at end of file +} diff --git a/libraries/GSM/src/GSM3ShieldV1VoiceProvider.cpp b/libraries/GSM/src/GSM3ShieldV1VoiceProvider.cpp index 98a50b900..e30f9390c 100644 --- a/libraries/GSM/src/GSM3ShieldV1VoiceProvider.cpp +++ b/libraries/GSM/src/GSM3ShieldV1VoiceProvider.cpp @@ -1,3 +1,36 @@ +/* +This file is part of the GSM3 communications library for Arduino +-- Multi-transport communications platform +-- Fully asynchronous +-- Includes code for the Arduino-Telefonica GSM/GPRS Shield V1 +-- Voice calls +-- SMS +-- TCP/IP connections +-- HTTP basic clients + +This library has been developed by Telefónica Digital - PDI - +- Physical Internet Lab, as part as its collaboration with +Arduino and the Open Hardware Community. + +September-December 2012 + +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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +The latest version of this library can always be found at +https://github.com/BlueVia/Official-Arduino +*/ #include #include diff --git a/libraries/LiquidCrystal/examples/setCursor/setCursor.ino b/libraries/LiquidCrystal/examples/setCursor/setCursor.ino index 4790b68b8..df75f7fe9 100644 --- a/libraries/LiquidCrystal/examples/setCursor/setCursor.ino +++ b/libraries/LiquidCrystal/examples/setCursor/setCursor.ino @@ -7,7 +7,7 @@ can usually tell them by the 16-pin interface. This sketch prints to all the positions of the LCD using the - setCursor(0 method: + setCursor() method: The circuit: * LCD RS pin to digital pin 12 @@ -56,9 +56,9 @@ void loop() { // loop from ASCII 'a' to ASCII 'z': for (int thisLetter = 'a'; thisLetter <= 'z'; thisLetter++) { // loop over the columns: - for (int thisCol = 0; thisCol < numRows; thisCol++) { + for (int thisRow = 0; thisRow < numRows; thisRow++) { // loop over the rows: - for (int thisRow = 0; thisRow < numCols; thisRow++) { + for (int thisCol = 0; thisCol < numCols; thisCol++) { // set the cursor position: lcd.setCursor(thisCol, thisRow); // print the letter: diff --git a/libraries/LiquidCrystal/keywords.txt b/libraries/LiquidCrystal/keywords.txt index 4ee24d90d..b6aa7fd90 100644 --- a/libraries/LiquidCrystal/keywords.txt +++ b/libraries/LiquidCrystal/keywords.txt @@ -6,7 +6,7 @@ # Datatypes (KEYWORD1) ####################################### -LiquidCrystal KEYWORD1 +LiquidCrystal KEYWORD1 LiquidCrystal ####################################### # Methods and Functions (KEYWORD2) diff --git a/libraries/LiquidCrystal/library.properties b/libraries/LiquidCrystal/library.properties index 4786c58c5..f379f78cc 100644 --- a/libraries/LiquidCrystal/library.properties +++ b/libraries/LiquidCrystal/library.properties @@ -1,9 +1,9 @@ -name=LiquidCrystal -version=1.0 -author=Arduino, Adafruit -maintainer=Arduino -sentence=Allows communication with alphanumerical liquid crystal displays (LCDs). For all Arduino boards. -paragraph=This library allows an Arduino board to control LiquidCrystal displays (LCDs) based on the Hitachi HD44780 (or a compatible) chipset, which is found on most text-based LCDs. The library works with in either 4 or 8 bit mode (i.e. using 4 or 8 data lines in addition to the rs, enable, and, optionally, the rw control lines). -category=Display -url=http://arduino.cc/en/Reference/LiquidCrystal -architectures=* +name=LiquidCrystal +version=1.0.1 +author=Arduino, Adafruit +maintainer=Arduino +sentence=Allows communication with alphanumerical liquid crystal displays (LCDs). For all Arduino boards. +paragraph=This library allows an Arduino board to control LiquidCrystal displays (LCDs) based on the Hitachi HD44780 (or a compatible) chipset, which is found on most text-based LCDs. The library works with in either 4 or 8 bit mode (i.e. using 4 or 8 data lines in addition to the rs, enable, and, optionally, the rw control lines). +category=Display +url=http://arduino.cc/en/Reference/LiquidCrystal +architectures=* diff --git a/libraries/LiquidCrystal/src/LiquidCrystal.cpp b/libraries/LiquidCrystal/src/LiquidCrystal.cpp index 249e0ec9b..9bf508b7b 100644 --- a/libraries/LiquidCrystal/src/LiquidCrystal.cpp +++ b/libraries/LiquidCrystal/src/LiquidCrystal.cpp @@ -158,12 +158,18 @@ void LiquidCrystal::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) { } +/* + in some 16x4 LCD when line 3 and 4 are not placed correctly you may try: + setRowOffsets(0x00, 0x40, 0x14, 0x54) + or + setRowOffsets(0x00, 0x40, 0x10, 0x50) + */ void LiquidCrystal::setRowOffsets(int row0, int row1, int row2, int row3) { - _row_offsets[0] = row0; - _row_offsets[1] = row1; - _row_offsets[2] = row2; - _row_offsets[3] = row3; + _row_offsets[0] = row0; + _row_offsets[1] = row1; + _row_offsets[2] = row2; + _row_offsets[3] = row3; } /********** high level commands, for the user! */ diff --git a/libraries/RobotIRremote/README.adoc b/libraries/RobotIRremote/README.adoc index 20a64ec76..54ce67c6d 100644 --- a/libraries/RobotIRremote/README.adoc +++ b/libraries/RobotIRremote/README.adoc @@ -8,6 +8,13 @@ http://arduino.cc/en/Reference/RobotLibrary == License == Copyright (c) Arduino LLC. All right reserved. +Copyright (c) Paul Stoffregen. All right reserved. +Copyright (c) Mitra Ardron. All right reserved. +Copyright (c) Joe Knapp. All right reserved. +Copyright (c) Mark Ivey. All right reserved. +Copyright (c) Kristian Lauszus. All right reserved. + +Copyright (c) 2009 Ken Shirriff. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public diff --git a/libraries/RobotIRremote/library.properties b/libraries/RobotIRremote/library.properties index da1f6c548..4db0bfa2b 100644 --- a/libraries/RobotIRremote/library.properties +++ b/libraries/RobotIRremote/library.properties @@ -1,5 +1,5 @@ name=Robot IR Remote -version=1.0 +version=1.0.1 author=Arduino maintainer=Arduino sentence=Allows controlling the Arduino Robot via an IR remote control. For Arduino Robot only. diff --git a/libraries/Robot_Control/README.adoc b/libraries/Robot_Control/README.adoc index 8a88feb7b..e0c1c472a 100644 --- a/libraries/Robot_Control/README.adoc +++ b/libraries/Robot_Control/README.adoc @@ -8,6 +8,9 @@ http://arduino.cc/en/Reference/RobotLibrary == License == Copyright (c) Arduino LLC. All right reserved. +Copyright (c) Bill Porter. All right reserved. +Copyright (C) 2008 by William Greiman. All right reserved. +Copyright (c) 2013 Adafruit Industries. All rights reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public diff --git a/libraries/Robot_Control/library.properties b/libraries/Robot_Control/library.properties index 4c070ffcd..994b0b0b1 100644 --- a/libraries/Robot_Control/library.properties +++ b/libraries/Robot_Control/library.properties @@ -1,5 +1,5 @@ name=Robot Control -version=1.0 +version=1.0.1 author=Arduino maintainer=Arduino sentence=Enables easy access to the controls of the Arduino Robot Control board. For Arduino Robot only. diff --git a/libraries/Robot_Control/src/Motors.cpp b/libraries/Robot_Control/src/Motors.cpp index 12096fd50..3555886a2 100644 --- a/libraries/Robot_Control/src/Motors.cpp +++ b/libraries/Robot_Control/src/Motors.cpp @@ -1 +1,113 @@ -#include "ArduinoRobot.h" #include "EasyTransfer2.h" void RobotControl::motorsStop(){ messageOut.writeByte(COMMAND_MOTORS_STOP); messageOut.sendData(); } void RobotControl::motorsWrite(int speedLeft,int speedRight){ messageOut.writeByte(COMMAND_RUN); messageOut.writeInt(speedLeft); messageOut.writeInt(speedRight); messageOut.sendData(); } void RobotControl::motorsWritePct(int speedLeftPct, int speedRightPct){ int16_t speedLeft=255*speedLeftPct/100.0; int16_t speedRight=255*speedRightPct/100.0; motorsWrite(speedLeft,speedRight); } void RobotControl::pointTo(int angle){ int target=angle; uint8_t speed=80; target=target%360; if(target<0){ target+=360; } int direction=angle; while(1){ int currentAngle=compassRead(); int diff=target-currentAngle; direction=180-(diff+360)%360; if(direction>0){ motorsWrite(speed,-speed);//right delay(10); }else{ motorsWrite(-speed,speed);//left delay(10); } //if(diff<-180) // diff += 360; //else if(diff> 180) // diff -= 360; //direction=-diff; if(abs(diff)<5){ motorsStop(); return; } } } void RobotControl::turn(int angle){ int originalAngle=compassRead(); int target=originalAngle+angle; pointTo(target); /*uint8_t speed=80; target=target%360; if(target<0){ target+=360; } int direction=angle; while(1){ if(direction>0){ motorsWrite(speed,speed);//right delay(10); }else{ motorsWrite(-speed,-speed);//left delay(10); } int currentAngle=compassRead(); int diff=target-currentAngle; if(diff<-180) diff += 360; else if(diff> 180) diff -= 360; direction=-diff; if(abs(diff)<5){ motorsWrite(0,0); return; } }*/ } void RobotControl::moveForward(int speed){ motorsWrite(speed,speed); } void RobotControl::moveBackward(int speed){ motorsWrite(speed,speed); } void RobotControl::turnLeft(int speed){ motorsWrite(speed,255); } void RobotControl::turnRight(int speed){ motorsWrite(255,speed); } /* int RobotControl::getIRrecvResult(){ messageOut.writeByte(COMMAND_GET_IRRECV); messageOut.sendData(); //delay(10); while(!messageIn.receiveData()); if(messageIn.readByte()==COMMAND_GET_IRRECV_RE){ return messageIn.readInt(); } return -1; } */ \ No newline at end of file +#include "ArduinoRobot.h" +#include "EasyTransfer2.h" + + +void RobotControl::motorsStop(){ + messageOut.writeByte(COMMAND_MOTORS_STOP); + messageOut.sendData(); +} +void RobotControl::motorsWrite(int speedLeft,int speedRight){ + messageOut.writeByte(COMMAND_RUN); + messageOut.writeInt(speedLeft); + messageOut.writeInt(speedRight); + messageOut.sendData(); +} +void RobotControl::motorsWritePct(int speedLeftPct, int speedRightPct){ + int16_t speedLeft=255*speedLeftPct/100.0; + int16_t speedRight=255*speedRightPct/100.0; + motorsWrite(speedLeft,speedRight); +} +void RobotControl::pointTo(int angle){ + int target=angle; + uint8_t speed=80; + target=target%360; + if(target<0){ + target+=360; + } + int direction=angle; + while(1){ + int currentAngle=compassRead(); + int diff=target-currentAngle; + direction=180-(diff+360)%360; + if(direction>0){ + motorsWrite(speed,-speed);//right + delay(10); + }else{ + motorsWrite(-speed,speed);//left + delay(10); + } + //if(diff<-180) + // diff += 360; + //else if(diff> 180) + // diff -= 360; + //direction=-diff; + + if(abs(diff)<5){ + motorsStop(); + return; + } + } +} +void RobotControl::turn(int angle){ + int originalAngle=compassRead(); + int target=originalAngle+angle; + pointTo(target); + /*uint8_t speed=80; + target=target%360; + if(target<0){ + target+=360; + } + int direction=angle; + while(1){ + if(direction>0){ + motorsWrite(speed,speed);//right + delay(10); + }else{ + motorsWrite(-speed,-speed);//left + delay(10); + } + int currentAngle=compassRead(); + int diff=target-currentAngle; + if(diff<-180) + diff += 360; + else if(diff> 180) + diff -= 360; + direction=-diff; + + if(abs(diff)<5){ + motorsWrite(0,0); + return; + } + }*/ +} + +void RobotControl::moveForward(int speed){ + motorsWrite(speed,speed); +} +void RobotControl::moveBackward(int speed){ + motorsWrite(speed,speed); +} +void RobotControl::turnLeft(int speed){ + motorsWrite(speed,255); +} +void RobotControl::turnRight(int speed){ + motorsWrite(255,speed); +} + + + +/* +int RobotControl::getIRrecvResult(){ + messageOut.writeByte(COMMAND_GET_IRRECV); + messageOut.sendData(); + //delay(10); + while(!messageIn.receiveData()); + + if(messageIn.readByte()==COMMAND_GET_IRRECV_RE){ + return messageIn.readInt(); + } + + + return -1; +} +*/ \ No newline at end of file diff --git a/libraries/Robot_Control/src/communication.cpp b/libraries/Robot_Control/src/communication.cpp index eaf5346c4..9e796c373 100644 --- a/libraries/Robot_Control/src/communication.cpp +++ b/libraries/Robot_Control/src/communication.cpp @@ -1 +1,29 @@ -#include bool RobotControl::isActionDone(){ if(messageIn.receiveData()){ if(messageIn.readByte()==COMMAND_ACTION_DONE){ return true; } } return false; } void RobotControl::pauseMode(uint8_t onOff){ messageOut.writeByte(COMMAND_PAUSE_MODE); if(onOff){ messageOut.writeByte(true); }else{ messageOut.writeByte(false); } messageOut.sendData(); } void RobotControl::lineFollowConfig(uint8_t KP, uint8_t KD, uint8_t robotSpeed, uint8_t intergrationTime){ messageOut.writeByte(COMMAND_LINE_FOLLOW_CONFIG); messageOut.writeByte(KP); messageOut.writeByte(KD); messageOut.writeByte(robotSpeed); messageOut.writeByte(intergrationTime); messageOut.sendData(); } \ No newline at end of file +#include + +bool RobotControl::isActionDone(){ + if(messageIn.receiveData()){ + if(messageIn.readByte()==COMMAND_ACTION_DONE){ + return true; + } + } + return false; +} + +void RobotControl::pauseMode(uint8_t onOff){ + messageOut.writeByte(COMMAND_PAUSE_MODE); + if(onOff){ + messageOut.writeByte(true); + }else{ + messageOut.writeByte(false); + } + messageOut.sendData(); +} + +void RobotControl::lineFollowConfig(uint8_t KP, uint8_t KD, uint8_t robotSpeed, uint8_t intergrationTime){ + messageOut.writeByte(COMMAND_LINE_FOLLOW_CONFIG); + messageOut.writeByte(KP); + messageOut.writeByte(KD); + messageOut.writeByte(robotSpeed); + messageOut.writeByte(intergrationTime); + messageOut.sendData(); +} diff --git a/libraries/Robot_Motor/library.properties b/libraries/Robot_Motor/library.properties index 326233f17..165412af2 100644 --- a/libraries/Robot_Motor/library.properties +++ b/libraries/Robot_Motor/library.properties @@ -1,5 +1,5 @@ name=Robot Motor -version=1.0 +version=1.0.1 author=Arduino maintainer=Arduino sentence=Enables easy access to the motors of the Arduino Robot Motor board. For Arduino Robot only. diff --git a/libraries/Robot_Motor/src/EasyTransfer2.cpp b/libraries/Robot_Motor/src/EasyTransfer2.cpp index 24427cc6e..bf1767876 100644 --- a/libraries/Robot_Motor/src/EasyTransfer2.cpp +++ b/libraries/Robot_Motor/src/EasyTransfer2.cpp @@ -1,3 +1,27 @@ +/****************************************************************** +* EasyTransfer Arduino Library +* details and example sketch: +* http://www.billporter.info/easytransfer-arduino-library/ +* +* Brought to you by: +* Bill Porter +* www.billporter.info +* +* See Readme for other info and version history +* +* +*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 3 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. + +* +*This work is licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported License. +*To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/ or +*send a letter to Creative Commons, 444 Castro Street, Suite 900, Mountain View, California, 94041, USA. +******************************************************************/ + #include "EasyTransfer2.h" @@ -149,4 +173,4 @@ boolean EasyTransfer2::receiveData(){ //Serial.print(" "); //Serial.println("Short"); return false; -} \ No newline at end of file +} diff --git a/libraries/SD/README.adoc b/libraries/SD/README.adoc index ec57d15ce..4c6521ed3 100644 --- a/libraries/SD/README.adoc +++ b/libraries/SD/README.adoc @@ -7,18 +7,18 @@ http://arduino.cc/en/Reference/SD == License == -Copyright (c) Arduino LLC. All right reserved. + Copyright (C) 2009 by William Greiman +Copyright (c) 2010 SparkFun Electronics -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 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 3 of the License, or +(at your option) any later version. -This library is distributed in the hope that it will be useful, +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 -Lesser General Public License for more details. +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 Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +You should have received a copy of the GNU General Public License +along with this program. If not, see . diff --git a/libraries/SD/examples/CardInfo/CardInfo.ino b/libraries/SD/examples/CardInfo/CardInfo.ino index 03bab2fd6..8d8a51ec9 100644 --- a/libraries/SD/examples/CardInfo/CardInfo.ino +++ b/libraries/SD/examples/CardInfo/CardInfo.ino @@ -44,19 +44,13 @@ void setup() Serial.print("\nInitializing SD card..."); - // On the Ethernet Shield, CS is pin 4. It's set as an output by default. - // Note that even if it's not used as the CS pin, the hardware SS pin - // (10 on most Arduino boards, 53 on the Mega) must be left as an output - // or the SD library functions will not work. - pinMode(10, OUTPUT); // change this to 53 on a mega - // we'll use the initialization code from the utility libraries // since we're just testing if the card is working! if (!card.init(SPI_HALF_SPEED, chipSelect)) { Serial.println("initialization failed. Things to check:"); - Serial.println("* is a card is inserted?"); - Serial.println("* Is your wiring correct?"); + Serial.println("* is a card inserted?"); + Serial.println("* is your wiring correct?"); Serial.println("* did you change the chipSelect pin to match your shield or module?"); return; } else { diff --git a/libraries/SD/examples/Datalogger/Datalogger.ino b/libraries/SD/examples/Datalogger/Datalogger.ino index 70e8f7051..e071b5282 100644 --- a/libraries/SD/examples/Datalogger/Datalogger.ino +++ b/libraries/SD/examples/Datalogger/Datalogger.ino @@ -23,10 +23,6 @@ #include #include -// On the Ethernet Shield, CS is pin 4. Note that even if it's not -// used as the CS pin, the hardware CS pin (10 on most Arduino boards, -// 53 on the Mega) must be left as an output or the SD library -// functions will not work. const int chipSelect = 4; void setup() @@ -39,9 +35,6 @@ void setup() Serial.print("Initializing SD card..."); - // make sure that the default chip select pin is set to - // output, even if you don't use it: - pinMode(10, OUTPUT); // see if the card is present and can be initialized: if (!SD.begin(chipSelect)) { diff --git a/libraries/SD/examples/DumpFile/DumpFile.ino b/libraries/SD/examples/DumpFile/DumpFile.ino index b2f510f58..e2eaf1c59 100644 --- a/libraries/SD/examples/DumpFile/DumpFile.ino +++ b/libraries/SD/examples/DumpFile/DumpFile.ino @@ -23,10 +23,6 @@ #include #include -// On the Ethernet Shield, CS is pin 4. Note that even if it's not -// used as the CS pin, the hardware CS pin (10 on most Arduino boards, -// 53 on the Mega) must be left as an output or the SD library -// functions will not work. const int chipSelect = 4; void setup() @@ -39,9 +35,6 @@ void setup() Serial.print("Initializing SD card..."); - // make sure that the default chip select pin is set to - // output, even if you don't use it: - pinMode(10, OUTPUT); // see if the card is present and can be initialized: if (!SD.begin(chipSelect)) { diff --git a/libraries/SD/examples/Files/Files.ino b/libraries/SD/examples/Files/Files.ino index d49539f38..f01db3828 100644 --- a/libraries/SD/examples/Files/Files.ino +++ b/libraries/SD/examples/Files/Files.ino @@ -32,11 +32,6 @@ void setup() Serial.print("Initializing SD card..."); - // On the Ethernet Shield, CS is pin 4. It's set as an output by default. - // Note that even if it's not used as the CS pin, the hardware SS pin - // (10 on most Arduino boards, 53 on the Mega) must be left as an output - // or the SD library functions will not work. - pinMode(10, OUTPUT); if (!SD.begin(4)) { Serial.println("initialization failed!"); diff --git a/libraries/SD/examples/ReadWrite/ReadWrite.ino b/libraries/SD/examples/ReadWrite/ReadWrite.ino index 42d1de388..055a0166b 100644 --- a/libraries/SD/examples/ReadWrite/ReadWrite.ino +++ b/libraries/SD/examples/ReadWrite/ReadWrite.ino @@ -33,11 +33,6 @@ void setup() Serial.print("Initializing SD card..."); - // On the Ethernet Shield, CS is pin 4. It's set as an output by default. - // Note that even if it's not used as the CS pin, the hardware SS pin - // (10 on most Arduino boards, 53 on the Mega) must be left as an output - // or the SD library functions will not work. - pinMode(10, OUTPUT); if (!SD.begin(4)) { Serial.println("initialization failed!"); diff --git a/libraries/SD/examples/listfiles/listfiles.ino b/libraries/SD/examples/listfiles/listfiles.ino index 22a79dd15..1500d74e0 100644 --- a/libraries/SD/examples/listfiles/listfiles.ino +++ b/libraries/SD/examples/listfiles/listfiles.ino @@ -35,11 +35,6 @@ void setup() } Serial.print("Initializing SD card..."); - // On the Ethernet Shield, CS is pin 4. It's set as an output by default. - // Note that even if it's not used as the CS pin, the hardware SS pin - // (10 on most Arduino boards, 53 on the Mega) must be left as an output - // or the SD library functions will not work. - pinMode(10, OUTPUT); if (!SD.begin(4)) { Serial.println("initialization failed!"); diff --git a/libraries/SD/keywords.txt b/libraries/SD/keywords.txt index 419fe04d5..9893cc91d 100644 --- a/libraries/SD/keywords.txt +++ b/libraries/SD/keywords.txt @@ -6,8 +6,8 @@ # Datatypes (KEYWORD1) ####################################### -SD KEYWORD1 -File KEYWORD1 +SD KEYWORD1 SD +File KEYWORD1 SD ####################################### # Methods and Functions (KEYWORD2) diff --git a/libraries/SD/library.properties b/libraries/SD/library.properties index ad4a6d686..4658054f8 100644 --- a/libraries/SD/library.properties +++ b/libraries/SD/library.properties @@ -1,9 +1,9 @@ -name=SD -version=1.0 -author=Arduino, SparkFun -maintainer=Arduino -sentence=Enables reading and writing on SD cards. For all Arduino boards. -paragraph=Once an SD memory card is connected to the SPI interfare of the Arduino board you are enabled to create files and read/write on them. You can also move through directories on the SD card. -category=Data Storage -url=http://arduino.cc/en/Reference/SD -architectures=* +name=SD +version=1.0.4 +author=Arduino, SparkFun +maintainer=Arduino +sentence=Enables reading and writing on SD cards. For all Arduino boards. +paragraph=Once an SD memory card is connected to the SPI interfare of the Arduino board you are enabled to create files and read/write on them. You can also move through directories on the SD card. +category=Data Storage +url=http://arduino.cc/en/Reference/SD +architectures=* diff --git a/libraries/SD/src/SD.cpp b/libraries/SD/src/SD.cpp index 6862daed8..28df356c8 100644 --- a/libraries/SD/src/SD.cpp +++ b/libraries/SD/src/SD.cpp @@ -448,7 +448,7 @@ File SDClass::open(const char *filepath, uint8_t mode) { // there is a special case for the Root directory since its a static dir if (parentdir.isRoot()) { - if ( ! file.open(SD.root, filepath, mode)) { + if ( ! file.open(root, filepath, mode)) { // failed to open the file :( return File(); } diff --git a/libraries/SD/src/SD.h b/libraries/SD/src/SD.h index 449984219..62276b4ee 100644 --- a/libraries/SD/src/SD.h +++ b/libraries/SD/src/SD.h @@ -48,6 +48,28 @@ public: boolean isDirectory(void); File openNextFile(uint8_t mode = O_RDONLY); void rewindDirectory(void); + + template size_t write(T &src){ + uint8_t obuf[512]; + size_t doneLen = 0; + size_t sentLen; + int i; + + while (src.available() > 512){ + src.read(obuf, 512); + sentLen = write(obuf, 512); + doneLen = doneLen + sentLen; + if(sentLen != 512){ + return doneLen; + } + } + + size_t leftLen = src.available(); + src.read(obuf, leftLen); + sentLen = write(obuf, leftLen); + doneLen = doneLen + sentLen; + return doneLen; + } using Print::write; }; @@ -84,6 +106,14 @@ public: boolean rmdir(char *filepath); + uint8_t type(){ return card.type(); } + uint8_t fatType(){ return volume.fatType(); } + size_t blocksPerCluster(){ return volume.blocksPerCluster(); } + size_t totalClusters(){ return volume.clusterCount(); } + size_t blockSize(){ return (size_t)0x200; } + size_t totalBlocks(){ return (totalClusters() / blocksPerCluster()); } + size_t clusterSize(){ return blocksPerCluster() * blockSize(); } + size_t size(){ return (clusterSize() * totalClusters()); } private: // This is used to determine the mode used to open a file diff --git a/libraries/SD/src/utility/Sd2Card.cpp b/libraries/SD/src/utility/Sd2Card.cpp index 2d7618d65..98b6e4e84 100644 --- a/libraries/SD/src/utility/Sd2Card.cpp +++ b/libraries/SD/src/utility/Sd2Card.cpp @@ -297,7 +297,7 @@ uint8_t Sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin) { // command to go idle in SPI mode while ((status_ = cardCommand(CMD0, 0)) != R1_IDLE_STATE) { - if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) { + if (((uint16_t)(millis() - t0)) > SD_INIT_TIMEOUT) { error(SD_CARD_ERROR_CMD0); goto fail; } @@ -319,7 +319,7 @@ uint8_t Sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin) { while ((status_ = cardAcmd(ACMD41, arg)) != R1_READY_STATE) { // check for timeout - if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) { + if (((uint16_t)(millis() - t0)) > SD_INIT_TIMEOUT) { error(SD_CARD_ERROR_ACMD41); goto fail; } diff --git a/libraries/Scheduler/README.adoc b/libraries/Scheduler/README.adoc index 860993b39..628bb1543 100644 --- a/libraries/Scheduler/README.adoc +++ b/libraries/Scheduler/README.adoc @@ -7,18 +7,16 @@ http://arduino.cc/en/Reference/Scheduler == License == -Copyright (c) Arduino LLC. All right reserved. +Copyright (c) 2012 The Android Open Source Project. All right reserved. -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. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -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. + http://www.apache.org/licenses/LICENSE-2.0 -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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/libraries/Scheduler/keywords.txt b/libraries/Scheduler/keywords.txt index 87313b8fc..6134de2b9 100644 --- a/libraries/Scheduler/keywords.txt +++ b/libraries/Scheduler/keywords.txt @@ -6,7 +6,7 @@ # Datatypes (KEYWORD1) ####################################### -Scheduler KEYWORD1 +Scheduler KEYWORD1 Scheduler ####################################### # Methods and Functions (KEYWORD2) diff --git a/libraries/Scheduler/library.properties b/libraries/Scheduler/library.properties index d247eb9d4..241208ce7 100644 --- a/libraries/Scheduler/library.properties +++ b/libraries/Scheduler/library.properties @@ -1,9 +1,9 @@ -name=Scheduler -version=0.4 -author=Arduino -maintainer=Arduino -sentence=Allows multiple tasks to run at the same time, without interrupting each other. For Arduino DUE only. -paragraph=The Scheduler library enables the Arduino Due to run multiple functions at the same time. This allows tasks to happen without interrupting each other.
This is a cooperative scheduler in that the CPU switches from one task to another. The library includes methods for passing control between tasks. -category=Other -url=http://arduino.cc/en/Reference/Scheduler -architectures=sam +name=Scheduler +version=0.4.2 +author=Arduino +maintainer=Arduino +sentence=Allows multiple tasks to run at the same time, without interrupting each other. For Arduino DUE only. +paragraph=The Scheduler library enables the Arduino Due to run multiple functions at the same time. This allows tasks to happen without interrupting each other.
This is a cooperative scheduler in that the CPU switches from one task to another. The library includes methods for passing control between tasks. +category=Other +url=http://arduino.cc/en/Reference/Scheduler +architectures=sam diff --git a/libraries/Servo/README.adoc b/libraries/Servo/README.adoc index 734e67095..a871b08c5 100644 --- a/libraries/Servo/README.adoc +++ b/libraries/Servo/README.adoc @@ -7,7 +7,8 @@ http://arduino.cc/en/Reference/Servo == License == -Copyright (c) Arduino LLC. All right reserved. +Copyright (c) 2013 Arduino LLC. All right reserved. +Copyright (c) 2009 Michael Margolis. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public diff --git a/libraries/Servo/keywords.txt b/libraries/Servo/keywords.txt index ca5ba79e3..0a7ca1e3d 100644 --- a/libraries/Servo/keywords.txt +++ b/libraries/Servo/keywords.txt @@ -6,7 +6,7 @@ # Datatypes (KEYWORD1) ####################################### -Servo KEYWORD1 +Servo KEYWORD1 Servo ####################################### # Methods and Functions (KEYWORD2) diff --git a/libraries/Servo/library.properties b/libraries/Servo/library.properties index 81eeacdb8..1712ac80f 100644 --- a/libraries/Servo/library.properties +++ b/libraries/Servo/library.properties @@ -1,5 +1,5 @@ name=Servo -version=1.0 +version=1.0.2 author=Michael Margolis, Arduino maintainer=Arduino sentence=Allows Arduino boards to control a variety of servo motors. For all Arduino boards. diff --git a/libraries/SpacebrewYun/library.properties b/libraries/SpacebrewYun/library.properties index c4b959d48..58af76d47 100644 --- a/libraries/SpacebrewYun/library.properties +++ b/libraries/SpacebrewYun/library.properties @@ -6,6 +6,6 @@ paragraph=This library was developed to enable you to easily connect the Arduino category=Communication url=https://github.com/julioterra/yunSpacebrew architectures=avr -version=1.0 +version=1.0.0 dependencies=Bridge core-dependencies=arduino (>=1.5.0) diff --git a/libraries/Stepper/README.adoc b/libraries/Stepper/README.adoc index 8982c5402..066623761 100644 --- a/libraries/Stepper/README.adoc +++ b/libraries/Stepper/README.adoc @@ -8,6 +8,8 @@ http://arduino.cc/en/Reference/Stepper == License == Copyright (c) Arduino LLC. All right reserved. +Copyright (c) Sebastian Gassner. All right reserved. +Copyright (c) Noah Shibley. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public diff --git a/libraries/Stepper/keywords.txt b/libraries/Stepper/keywords.txt index 19a0fadf2..5e58a66b0 100644 --- a/libraries/Stepper/keywords.txt +++ b/libraries/Stepper/keywords.txt @@ -6,7 +6,7 @@ # Datatypes (KEYWORD1) ####################################### -Stepper KEYWORD1 +Stepper KEYWORD1 Stepper ####################################### # Methods and Functions (KEYWORD2) diff --git a/libraries/Stepper/library.properties b/libraries/Stepper/library.properties index 30b7cea44..f17170344 100644 --- a/libraries/Stepper/library.properties +++ b/libraries/Stepper/library.properties @@ -1,9 +1,9 @@ -name=Stepper -version=1.0 -author=Arduino -maintainer=Arduino -sentence=Allows Arduino boards to control a variety of stepper motors. For all Arduino boards. -paragraph=This library allows you to control unipolar or bipolar stepper motors. To use it you will need a stepper motor, and the appropriate hardware to control it. -category=Device Control -url=http://arduino.cc/en/Reference/Stepper -architectures=* +name=Stepper +version=1.0.2 +author=Arduino +maintainer=Arduino +sentence=Allows Arduino boards to control a variety of stepper motors. For all Arduino boards. +paragraph=This library allows you to control unipolar or bipolar stepper motors. To use it you will need a stepper motor, and the appropriate hardware to control it. +category=Device Control +url=http://arduino.cc/en/Reference/Stepper +architectures=* diff --git a/libraries/Stepper/src/Stepper.cpp b/libraries/Stepper/src/Stepper.cpp index 5d6b5e536..b1cbee6d1 100644 --- a/libraries/Stepper/src/Stepper.cpp +++ b/libraries/Stepper/src/Stepper.cpp @@ -40,7 +40,20 @@ The circuits can be found at http://www.arduino.cc/en/Tutorial/Stepper - + +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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ diff --git a/libraries/Stepper/src/Stepper.h b/libraries/Stepper/src/Stepper.h index 4094aee90..e0441ffe7 100644 --- a/libraries/Stepper/src/Stepper.h +++ b/libraries/Stepper/src/Stepper.h @@ -39,6 +39,20 @@ The circuits can be found at http://www.arduino.cc/en/Tutorial/Stepper + +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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ // ensure this library description is only included once diff --git a/libraries/TFT/README.adoc b/libraries/TFT/README.adoc index 19c9bafba..ab716292b 100644 --- a/libraries/TFT/README.adoc +++ b/libraries/TFT/README.adoc @@ -8,6 +8,8 @@ http://arduino.cc/en/Reference/TFTLibrary == License == Copyright (c) Arduino LLC. All right reserved. +Copyright (c) Enrico Gueli. All right reserved. +Copyright (c) 2012, Adafruit Industries. All rights reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public diff --git a/libraries/TFT/keywords.txt b/libraries/TFT/keywords.txt index 0ddb3b536..c8d33e416 100644 --- a/libraries/TFT/keywords.txt +++ b/libraries/TFT/keywords.txt @@ -6,7 +6,7 @@ # Datatypes (KEYWORD1) ####################################### -TFT KEYWORD1 +TFT KEYWORD1 TFTLibrary ####################################### # Methods and Functions (KEYWORD2) diff --git a/libraries/TFT/library.properties b/libraries/TFT/library.properties index 68ea4b6e4..a46758741 100644 --- a/libraries/TFT/library.properties +++ b/libraries/TFT/library.properties @@ -1,9 +1,9 @@ -name=TFT -version=1.0 -author=Arduino, Adafruit -maintainer=Arduino -sentence=Allows drawing text, images, and shapes on the Arduino TFT graphical display. For all Arduino boards. -paragraph=This library is compatible with most of the TFT display based on the ST7735 chipset -category=Display -url=http://arduino.cc/en/Reference/TFTLibrary -architectures=* +name=TFT +version=1.0.2 +author=Arduino, Adafruit +maintainer=Arduino +sentence=Allows drawing text, images, and shapes on the Arduino TFT graphical display. For all Arduino boards. +paragraph=This library is compatible with most of the TFT display based on the ST7735 chipset +category=Display +url=http://arduino.cc/en/Reference/TFTLibrary +architectures=* diff --git a/libraries/TFT/src/TFT.cpp b/libraries/TFT/src/TFT.cpp index 3b15d25d8..1bdf7ed3c 100644 --- a/libraries/TFT/src/TFT.cpp +++ b/libraries/TFT/src/TFT.cpp @@ -1,3 +1,34 @@ +/* Copyright (c) 2013, Enrico Gueli All +rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + #include "TFT.h" #if ARDUINO_AVR_ESPLORA diff --git a/libraries/TFT/src/TFT.h b/libraries/TFT/src/TFT.h index 39cb5c14a..16791d6bb 100644 --- a/libraries/TFT/src/TFT.h +++ b/libraries/TFT/src/TFT.h @@ -1,3 +1,33 @@ +/* Copyright (c) 2013, Enrico Gueli All +rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ #ifndef _ARDUINO_TFT_H #define _ARDUINO_TFT_H diff --git a/libraries/Temboo/README.adoc b/libraries/Temboo/README.adoc index 155b6f690..ec74a12d4 100644 --- a/libraries/Temboo/README.adoc +++ b/libraries/Temboo/README.adoc @@ -4,18 +4,16 @@ This library allows an Arduino Yun to connect to the Temboo service. == License == -Copyright (c) Arduino LLC. All right reserved. - -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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +Copyright 2015, Temboo Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +either express or implied. See the License for the specific +language governing permissions and limitations under the License. diff --git a/libraries/Temboo/keywords.txt b/libraries/Temboo/keywords.txt index f4565ea31..40d670dd7 100644 --- a/libraries/Temboo/keywords.txt +++ b/libraries/Temboo/keywords.txt @@ -3,10 +3,10 @@ ####################################### ####################################### -# Class (KEYWORD3) +# Class (KEYWORD1) ####################################### -Temboo KEYWORD3 +Temboo KEYWORD1 ####################################### # Datatypes (KEYWORD2) diff --git a/libraries/Temboo/library.properties b/libraries/Temboo/library.properties index 3ae1c9451..9b743a33a 100644 --- a/libraries/Temboo/library.properties +++ b/libraries/Temboo/library.properties @@ -6,5 +6,5 @@ paragraph=Use this library to connect your Arduino board to Temboo, making it si category=Communication url=http://www.temboo.com/arduino architectures=* -version=1.1 +version=1.1.2 core-dependencies=arduino (>=1.5.0) diff --git a/libraries/Temboo/src/Temboo.cpp b/libraries/Temboo/src/Temboo.cpp index f7ddaf93e..f4eb85e7f 100644 --- a/libraries/Temboo/src/Temboo.cpp +++ b/libraries/Temboo/src/Temboo.cpp @@ -3,7 +3,7 @@ # # Temboo Arduino library # -# Copyright 2014, Temboo Inc. +# Copyright 2015, Temboo Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -92,6 +92,8 @@ void TembooChoreo::setSettingsFileToRead(const String& filePath) { #include "utility/TembooSession.h" static const char HTTP_CODE[] PROGMEM = "HTTP_CODE\x0A\x1F"; +static char HTTP_EOL[] = "\r\n"; +static char HTTP_EOH[] = "\r\n\r\n"; TembooChoreo::TembooChoreo(Client& client) : m_client(client) { m_accountName = NULL; @@ -171,7 +173,6 @@ void TembooChoreo::setProfile(const char* profileName) { } - void TembooChoreo::addInput(const String& inputName, const String& inputValue) { m_inputs.put(inputName.c_str(), inputValue.c_str()); } @@ -233,66 +234,76 @@ void TembooChoreo::addOutputFilter(const String& outputName, const String& filte int TembooChoreo::run() { - return run(INADDR_NONE, 80); + return run(INADDR_NONE, 80, TEMBOO_CHOREO_DEFAULT_TIMEOUT_SECS); } +int TembooChoreo::run(uint16_t timeoutSecs) { + return run(INADDR_NONE, 80, timeoutSecs); +} -int TembooChoreo::run(IPAddress addr, uint16_t port) { - +int TembooChoreo::run(IPAddress addr, uint16_t port, uint16_t timeoutSecs) { + m_nextChar = NULL; - + if (m_accountName == NULL || *m_accountName == '\0') { return TEMBOO_ERROR_ACCOUNT_MISSING; } - + if (m_path == NULL || *m_path == '\0') { return TEMBOO_ERROR_CHOREO_MISSING; } - + if (m_appKeyName == NULL || *m_appKeyName == '\0') { return TEMBOO_ERROR_APPKEY_NAME_MISSING; } - + if (m_appKeyValue == NULL || *m_appKeyValue == '\0') { return TEMBOO_ERROR_APPKEY_MISSING; } - - + TembooSession session(m_client, addr, port); uint16_t httpCode = 0; for (int i = 0; i < 2; i++) { + unsigned long timeoutBeginSecs = session.getTime(); if (0 != session.executeChoreo(m_accountName, m_appKeyName, m_appKeyValue, m_path, m_inputs, m_outputs, m_preset)) { httpCode = 0; break; } - + while(!m_client.available()) { + if((session.getTime() - timeoutBeginSecs) >= timeoutSecs) { + TEMBOO_TRACELN("Receive time out"); + m_client.stop(); + return TEMBOO_ERROR_STREAM_TIMEOUT; + } if (!m_client.connected()) { TEMBOO_TRACELN("Disconnected"); return TEMBOO_ERROR_HTTP_ERROR; } delay(10); } - - if (!m_client.find("HTTP/1.1 ")) { + if (!m_client.findUntil("HTTP/1.", HTTP_EOL)) { TEMBOO_TRACELN("No HTTP"); return TEMBOO_ERROR_HTTP_ERROR; } - + //Don't care if the next byte is a '1' or a '0' + m_client.read(); + + //Read the HTTP status code httpCode = (uint16_t)m_client.parseInt(); - - // We expect HTTP response codes to be <= 599, but + + // We expect HTTP response codes to be <= 599, but // we need to be prepared for anything. if (httpCode >= 600) { TEMBOO_TRACELN("Invalid HTTP"); httpCode = 0; } - + // if we get an auth error AND there was an x-temboo-time header, // update the session timeOffset if ((httpCode == 401) && (i == 0)) { - if (m_client.find("x-temboo-time:")) { + if (m_client.findUntil("x-temboo-time:", HTTP_EOH)) { TembooSession::setTime((unsigned long)m_client.parseInt()); while(m_client.available()) { m_client.read(); @@ -303,20 +314,20 @@ int TembooChoreo::run(IPAddress addr, uint16_t port) { break; } } - + uint16toa(httpCode, m_httpCodeStr); strcat_P(m_httpCodeStr, PSTR("\x0A\x1E")); m_nextState = START; m_nextChar = HTTP_CODE; - + if (httpCode < 200 || httpCode >= 300) { return TEMBOO_ERROR_HTTP_ERROR; } - - if (!m_client.find("\x0D\x0A\x0D\x0A")) { + + if (!m_client.find(HTTP_EOH)) { return TEMBOO_ERROR_HTTP_ERROR; } - + return TEMBOO_ERROR_OK; } diff --git a/libraries/Temboo/src/Temboo.h b/libraries/Temboo/src/Temboo.h index 3b1b7ec40..881fe484a 100644 --- a/libraries/Temboo/src/Temboo.h +++ b/libraries/Temboo/src/Temboo.h @@ -3,7 +3,7 @@ # # Temboo Arduino library # -# Copyright 2014, Temboo Inc. +# Copyright 2015, Temboo Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -69,6 +69,8 @@ class TembooChoreo : public Process { #define TEMBOO_ERROR_APPKEY_NAME_MISSING (205) #define TEMBOO_ERROR_APPKEY_MISSING (207) #define TEMBOO_ERROR_HTTP_ERROR (223) +#define TEMBOO_ERROR_STREAM_TIMEOUT (225) +#define TEMBOO_CHOREO_DEFAULT_TIMEOUT_SECS (901) //15 minutes and 1 second class TembooChoreo : public Stream { public: @@ -135,7 +137,8 @@ class TembooChoreo : public Stream { // run the choreo on the Temboo server at the given IP address and port // (used only when instructed by Temboo customer support.) - int run(IPAddress addr, uint16_t port); + int run(uint16_t timeoutSecs); + int run(IPAddress addr, uint16_t port, uint16_t timeoutSecs); void close(); diff --git a/libraries/Temboo/src/utility/BaseFormatter.cpp b/libraries/Temboo/src/utility/BaseFormatter.cpp index b9b77db67..1e575e217 100644 --- a/libraries/Temboo/src/utility/BaseFormatter.cpp +++ b/libraries/Temboo/src/utility/BaseFormatter.cpp @@ -3,7 +3,7 @@ # # Temboo Arduino library # -# Copyright 2014, Temboo Inc. +# Copyright 2015, Temboo Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/libraries/Temboo/src/utility/BaseFormatter.h b/libraries/Temboo/src/utility/BaseFormatter.h index d8886ad13..3d4443124 100644 --- a/libraries/Temboo/src/utility/BaseFormatter.h +++ b/libraries/Temboo/src/utility/BaseFormatter.h @@ -3,7 +3,7 @@ # # Temboo Arduino library # -# Copyright 2014, Temboo Inc. +# Copyright 2015, Temboo Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/libraries/Temboo/src/utility/ChoreoInput.cpp b/libraries/Temboo/src/utility/ChoreoInput.cpp index 00138b7a3..faf921d89 100644 --- a/libraries/Temboo/src/utility/ChoreoInput.cpp +++ b/libraries/Temboo/src/utility/ChoreoInput.cpp @@ -3,7 +3,7 @@ # # Temboo Arduino library # -# Copyright 2014, Temboo Inc. +# Copyright 2015, Temboo Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/libraries/Temboo/src/utility/ChoreoInput.h b/libraries/Temboo/src/utility/ChoreoInput.h index 3e2b8b83a..a23ca700c 100644 --- a/libraries/Temboo/src/utility/ChoreoInput.h +++ b/libraries/Temboo/src/utility/ChoreoInput.h @@ -3,7 +3,7 @@ # # Temboo Arduino library # -# Copyright 2014, Temboo Inc. +# Copyright 2015, Temboo Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/libraries/Temboo/src/utility/ChoreoInputFormatter.cpp b/libraries/Temboo/src/utility/ChoreoInputFormatter.cpp index e70bd8aab..a54c55375 100644 --- a/libraries/Temboo/src/utility/ChoreoInputFormatter.cpp +++ b/libraries/Temboo/src/utility/ChoreoInputFormatter.cpp @@ -3,7 +3,7 @@ # # Temboo Arduino library # -# Copyright 2014, Temboo Inc. +# Copyright 2015, Temboo Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/libraries/Temboo/src/utility/ChoreoInputFormatter.h b/libraries/Temboo/src/utility/ChoreoInputFormatter.h index 78b2f9776..8946c5d10 100644 --- a/libraries/Temboo/src/utility/ChoreoInputFormatter.h +++ b/libraries/Temboo/src/utility/ChoreoInputFormatter.h @@ -3,7 +3,7 @@ # # Temboo Arduino library # -# Copyright 2014, Temboo Inc. +# Copyright 2015, Temboo Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/libraries/Temboo/src/utility/ChoreoInputSet.cpp b/libraries/Temboo/src/utility/ChoreoInputSet.cpp index 5257a1695..09a9f1aac 100644 --- a/libraries/Temboo/src/utility/ChoreoInputSet.cpp +++ b/libraries/Temboo/src/utility/ChoreoInputSet.cpp @@ -3,7 +3,7 @@ # # Temboo Arduino library # -# Copyright 2014, Temboo Inc. +# Copyright 2015, Temboo Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/libraries/Temboo/src/utility/ChoreoInputSet.h b/libraries/Temboo/src/utility/ChoreoInputSet.h index 4349049c5..123a38a23 100644 --- a/libraries/Temboo/src/utility/ChoreoInputSet.h +++ b/libraries/Temboo/src/utility/ChoreoInputSet.h @@ -3,7 +3,7 @@ # # Temboo Arduino library # -# Copyright 2014, Temboo Inc. +# Copyright 2015, Temboo Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/libraries/Temboo/src/utility/ChoreoOutput.cpp b/libraries/Temboo/src/utility/ChoreoOutput.cpp index 63ede6bf5..63cdc5fda 100644 --- a/libraries/Temboo/src/utility/ChoreoOutput.cpp +++ b/libraries/Temboo/src/utility/ChoreoOutput.cpp @@ -3,7 +3,7 @@ # # Temboo Arduino library # -# Copyright 2014, Temboo Inc. +# Copyright 2015, Temboo Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/libraries/Temboo/src/utility/ChoreoOutput.h b/libraries/Temboo/src/utility/ChoreoOutput.h index a026d955d..844e8b5fb 100644 --- a/libraries/Temboo/src/utility/ChoreoOutput.h +++ b/libraries/Temboo/src/utility/ChoreoOutput.h @@ -3,7 +3,7 @@ # # Temboo Arduino library # -# Copyright 2014, Temboo Inc. +# Copyright 2015, Temboo Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/libraries/Temboo/src/utility/ChoreoOutputFormatter.cpp b/libraries/Temboo/src/utility/ChoreoOutputFormatter.cpp index a4b581bb1..53561ccd8 100644 --- a/libraries/Temboo/src/utility/ChoreoOutputFormatter.cpp +++ b/libraries/Temboo/src/utility/ChoreoOutputFormatter.cpp @@ -3,7 +3,7 @@ # # Temboo Arduino library # -# Copyright 2014, Temboo Inc. +# Copyright 2015, Temboo Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/libraries/Temboo/src/utility/ChoreoOutputFormatter.h b/libraries/Temboo/src/utility/ChoreoOutputFormatter.h index c1086fc57..52874a6ca 100644 --- a/libraries/Temboo/src/utility/ChoreoOutputFormatter.h +++ b/libraries/Temboo/src/utility/ChoreoOutputFormatter.h @@ -3,7 +3,7 @@ # # Temboo Arduino library # -# Copyright 2014, Temboo Inc. +# Copyright 2015, Temboo Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/libraries/Temboo/src/utility/ChoreoOutputSet.cpp b/libraries/Temboo/src/utility/ChoreoOutputSet.cpp index f61b83fd9..084fe625b 100644 --- a/libraries/Temboo/src/utility/ChoreoOutputSet.cpp +++ b/libraries/Temboo/src/utility/ChoreoOutputSet.cpp @@ -3,7 +3,7 @@ # # Temboo Arduino library # -# Copyright 2014, Temboo Inc. +# Copyright 2015, Temboo Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/libraries/Temboo/src/utility/ChoreoOutputSet.h b/libraries/Temboo/src/utility/ChoreoOutputSet.h index b15808980..2c0fc4b9c 100644 --- a/libraries/Temboo/src/utility/ChoreoOutputSet.h +++ b/libraries/Temboo/src/utility/ChoreoOutputSet.h @@ -3,7 +3,7 @@ # # Temboo Arduino library # -# Copyright 2014, Temboo Inc. +# Copyright 2015, Temboo Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/libraries/Temboo/src/utility/ChoreoPreset.cpp b/libraries/Temboo/src/utility/ChoreoPreset.cpp index 8b637001b..61a785026 100644 --- a/libraries/Temboo/src/utility/ChoreoPreset.cpp +++ b/libraries/Temboo/src/utility/ChoreoPreset.cpp @@ -3,7 +3,7 @@ # # Temboo Arduino library # -# Copyright 2014, Temboo Inc. +# Copyright 2015, Temboo Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/libraries/Temboo/src/utility/ChoreoPreset.h b/libraries/Temboo/src/utility/ChoreoPreset.h index b48b14262..2ba457b6d 100644 --- a/libraries/Temboo/src/utility/ChoreoPreset.h +++ b/libraries/Temboo/src/utility/ChoreoPreset.h @@ -3,7 +3,7 @@ # # Temboo Arduino library # -# Copyright 2014, Temboo Inc. +# Copyright 2015, Temboo Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/libraries/Temboo/src/utility/ChoreoPresetFormatter.cpp b/libraries/Temboo/src/utility/ChoreoPresetFormatter.cpp index a5b8e2891..f34d181a5 100644 --- a/libraries/Temboo/src/utility/ChoreoPresetFormatter.cpp +++ b/libraries/Temboo/src/utility/ChoreoPresetFormatter.cpp @@ -3,7 +3,7 @@ # # Temboo Arduino library # -# Copyright 2014, Temboo Inc. +# Copyright 2015, Temboo Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/libraries/Temboo/src/utility/ChoreoPresetFormatter.h b/libraries/Temboo/src/utility/ChoreoPresetFormatter.h index a0ffaf984..30e4a9b1f 100644 --- a/libraries/Temboo/src/utility/ChoreoPresetFormatter.h +++ b/libraries/Temboo/src/utility/ChoreoPresetFormatter.h @@ -3,7 +3,7 @@ # # Temboo Arduino library # -# Copyright 2014, Temboo Inc. +# Copyright 2015, Temboo Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/libraries/Temboo/src/utility/DataFormatter.cpp b/libraries/Temboo/src/utility/DataFormatter.cpp index 7291da94e..f5cdf989b 100644 --- a/libraries/Temboo/src/utility/DataFormatter.cpp +++ b/libraries/Temboo/src/utility/DataFormatter.cpp @@ -3,7 +3,7 @@ # # Temboo Arduino library # -# Copyright 2014, Temboo Inc. +# Copyright 2015, Temboo Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/libraries/Temboo/src/utility/DataFormatter.h b/libraries/Temboo/src/utility/DataFormatter.h index 0ee110f87..542c821d1 100644 --- a/libraries/Temboo/src/utility/DataFormatter.h +++ b/libraries/Temboo/src/utility/DataFormatter.h @@ -3,7 +3,7 @@ # # Temboo Arduino library # -# Copyright 2014, Temboo Inc. +# Copyright 2015, Temboo Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/libraries/Temboo/src/utility/TembooGlobal.c b/libraries/Temboo/src/utility/TembooGlobal.c index 256ea2ea9..63163c1af 100644 --- a/libraries/Temboo/src/utility/TembooGlobal.c +++ b/libraries/Temboo/src/utility/TembooGlobal.c @@ -3,7 +3,7 @@ # # Temboo Arduino library # -# Copyright 2014, Temboo Inc. +# Copyright 2015, Temboo Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/libraries/Temboo/src/utility/TembooGlobal.h b/libraries/Temboo/src/utility/TembooGlobal.h index 91d16585c..acb89437b 100644 --- a/libraries/Temboo/src/utility/TembooGlobal.h +++ b/libraries/Temboo/src/utility/TembooGlobal.h @@ -3,7 +3,7 @@ # # Temboo Arduino library # -# Copyright 2014, Temboo Inc. +# Copyright 2015, Temboo Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/libraries/Temboo/src/utility/TembooSession.cpp b/libraries/Temboo/src/utility/TembooSession.cpp index bdd7e229a..70dbb9e9e 100644 --- a/libraries/Temboo/src/utility/TembooSession.cpp +++ b/libraries/Temboo/src/utility/TembooSession.cpp @@ -3,7 +3,7 @@ # # Temboo Arduino library # -# Copyright 2014, Temboo Inc. +# Copyright 2015, Temboo Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/libraries/Temboo/src/utility/TembooSession.h b/libraries/Temboo/src/utility/TembooSession.h index 403ed8eb6..635467f6b 100644 --- a/libraries/Temboo/src/utility/TembooSession.h +++ b/libraries/Temboo/src/utility/TembooSession.h @@ -3,7 +3,7 @@ # # Temboo Arduino library # -# Copyright 2014, Temboo Inc. +# Copyright 2015, Temboo Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/libraries/Temboo/src/utility/tmbhmac.cpp b/libraries/Temboo/src/utility/tmbhmac.cpp index 736e60d44..9e23763aa 100644 --- a/libraries/Temboo/src/utility/tmbhmac.cpp +++ b/libraries/Temboo/src/utility/tmbhmac.cpp @@ -3,7 +3,7 @@ # # Temboo Arduino library # -# Copyright 2014, Temboo Inc. +# Copyright 2015, Temboo Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/libraries/Temboo/src/utility/tmbhmac.h b/libraries/Temboo/src/utility/tmbhmac.h index 6652dbf82..028b2bd97 100644 --- a/libraries/Temboo/src/utility/tmbhmac.h +++ b/libraries/Temboo/src/utility/tmbhmac.h @@ -3,7 +3,7 @@ # # Temboo Arduino library # -# Copyright 2014, Temboo Inc. +# Copyright 2015, Temboo Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/libraries/Temboo/src/utility/tmbmd5.cpp b/libraries/Temboo/src/utility/tmbmd5.cpp index e270c1c27..fe8d7a9d3 100644 --- a/libraries/Temboo/src/utility/tmbmd5.cpp +++ b/libraries/Temboo/src/utility/tmbmd5.cpp @@ -3,7 +3,7 @@ # # Temboo Arduino library # -# Copyright 2014, Temboo Inc. +# Copyright 2015, Temboo Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/libraries/Temboo/src/utility/tmbmd5.h b/libraries/Temboo/src/utility/tmbmd5.h index 3a0bcf0e6..9c22c4376 100644 --- a/libraries/Temboo/src/utility/tmbmd5.h +++ b/libraries/Temboo/src/utility/tmbmd5.h @@ -3,7 +3,7 @@ # # Temboo Arduino library # -# Copyright 2014, Temboo Inc. +# Copyright 2015, Temboo Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/libraries/USBHost/README.adoc b/libraries/USBHost/README.adoc index 4b79236a2..cd617a9f7 100644 --- a/libraries/USBHost/README.adoc +++ b/libraries/USBHost/README.adoc @@ -7,7 +7,8 @@ http://arduino.cc/en/Reference/USBHost == License == -Copyright (c) Arduino LLC. All right reserved. +Copyright (c) 2012 Arduino LLC. All right reserved. +Copyright (c) 2011 Circuits At Home, LTD. All rights reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public diff --git a/libraries/USBHost/keywords.txt b/libraries/USBHost/keywords.txt index dded4dcf7..1ace20256 100644 --- a/libraries/USBHost/keywords.txt +++ b/libraries/USBHost/keywords.txt @@ -6,15 +6,15 @@ # Datatypes (KEYWORD1) ####################################### -MouseController KEYWORD1 -USBHost KEYWORD1 -KeyboardController KEYWORD1 +MouseController KEYWORD1 MouseControllerConstructor +USBHost KEYWORD1 USBHost +KeyboardController KEYWORD1 KeyboardControllerConstructor ####################################### # Methods and Functions (KEYWORD2) ####################################### -Task KEYWORD2 +Task KEYWORD2 USBHostTask mouseMoved KEYWORD2 mouseDragged KEYWORD2 mousePressed KEYWORD2 diff --git a/libraries/USBHost/library.properties b/libraries/USBHost/library.properties index 37f605a25..765a0d6fe 100644 --- a/libraries/USBHost/library.properties +++ b/libraries/USBHost/library.properties @@ -1,9 +1,9 @@ -name=USBHost -version=1.0 -author=Arduino -maintainer=Arduino -sentence=Allows the communication with USB peripherals like mice, keyboards, and thumbdrives. For Arduino DUE only. -paragraph=The USBHost library allows an Arduino Due board to appear as a USB host, enabling it to communicate with peripherals like USB mice and keyboards. USBHost does not support devices that are connected through USB hubs. This includes some keyboards that have an internal hub. -category=Device Control -url=http://arduino.cc/en/Reference/USBHost -architectures=sam +name=USBHost +version=1.0.2 +author=Arduino +maintainer=Arduino +sentence=Allows the communication with USB peripherals like mice, keyboards, and thumbdrives. For Arduino DUE only. +paragraph=The USBHost library allows an Arduino Due board to appear as a USB host, enabling it to communicate with peripherals like USB mice and keyboards. USBHost does not support devices that are connected through USB hubs. This includes some keyboards that have an internal hub. +category=Device Control +url=http://arduino.cc/en/Reference/USBHost +architectures=sam diff --git a/libraries/USBHost/src/KeyboardController.cpp b/libraries/USBHost/src/KeyboardController.cpp index 70c769f64..22eebb6ed 100644 --- a/libraries/USBHost/src/KeyboardController.cpp +++ b/libraries/USBHost/src/KeyboardController.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2012 Arduino. All right reserved. + Copyright (c) 2012 Arduino LLC. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public diff --git a/libraries/USBHost/src/KeyboardController.h b/libraries/USBHost/src/KeyboardController.h index e1b891bff..00682c675 100644 --- a/libraries/USBHost/src/KeyboardController.h +++ b/libraries/USBHost/src/KeyboardController.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2012 Arduino. All right reserved. + Copyright (c) 2012 Arduino LLC. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public diff --git a/libraries/USBHost/src/MouseController.cpp b/libraries/USBHost/src/MouseController.cpp index 3d528bc37..2416115ca 100644 --- a/libraries/USBHost/src/MouseController.cpp +++ b/libraries/USBHost/src/MouseController.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2012 Arduino. All right reserved. + Copyright (c) 2012 Arduino LLC. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public diff --git a/libraries/USBHost/src/MouseController.h b/libraries/USBHost/src/MouseController.h index 4c8c65e9c..427a8570e 100644 --- a/libraries/USBHost/src/MouseController.h +++ b/libraries/USBHost/src/MouseController.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2012 Arduino. All right reserved. + Copyright (c) 2012 Arduino LLC. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public diff --git a/libraries/WiFi/README.adoc b/libraries/WiFi/README.adoc new file mode 100644 index 000000000..90a37d210 --- /dev/null +++ b/libraries/WiFi/README.adoc @@ -0,0 +1,27 @@ += WiFi Library for Arduino = + +With the Arduino WiFi Shield, this library allows an Arduino board to connect to the internet. + +For more information about this library please visit us at +http://arduino.cc/en/Reference/WiFi + +== License == + +Copyright (c) 2011-2014 Arduino LLC. All right reserved. +Copyright (C) 2006-2008, Atmel Corporation All rights reserved. +Copyright (c) 2001-2004 Swedish Institute of Computer Science. +Copyright (c) 2009-2010, H&D Wireless AB All rights reserved. + +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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA diff --git a/libraries/WiFi/src/WiFi.cpp b/libraries/WiFi/src/WiFi.cpp new file mode 100644 index 000000000..4cb750e63 --- /dev/null +++ b/libraries/WiFi/src/WiFi.cpp @@ -0,0 +1,250 @@ +/* + WiFi.cpp - Library for Arduino Wifi shield. + Copyright (c) 2011-2014 Arduino LLC. All right reserved. + + 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "utility/wifi_drv.h" +#include "WiFi.h" + +extern "C" { + #include "utility/wl_definitions.h" + #include "utility/wl_types.h" + #include "utility/debug.h" +} + +// XXX: don't make assumptions about the value of MAX_SOCK_NUM. +int16_t WiFiClass::_state[MAX_SOCK_NUM] = { NA_STATE, NA_STATE, NA_STATE, NA_STATE }; +uint16_t WiFiClass::_server_port[MAX_SOCK_NUM] = { 0, 0, 0, 0 }; + +WiFiClass::WiFiClass() +{ + // Driver initialization + init(); +} + +void WiFiClass::init() +{ + WiFiDrv::wifiDriverInit(); +} + +uint8_t WiFiClass::getSocket() +{ + for (uint8_t i = 0; i < MAX_SOCK_NUM; ++i) + { + if (WiFiClass::_server_port[i] == 0) + { + return i; + } + } + return NO_SOCKET_AVAIL; +} + +char* WiFiClass::firmwareVersion() +{ + return WiFiDrv::getFwVersion(); +} + +int WiFiClass::begin(char* ssid) +{ + uint8_t status = WL_IDLE_STATUS; + uint8_t attempts = WL_MAX_ATTEMPT_CONNECTION; + + if (WiFiDrv::wifiSetNetwork(ssid, strlen(ssid)) != WL_FAILURE) + { + do + { + delay(WL_DELAY_START_CONNECTION); + status = WiFiDrv::getConnectionStatus(); + } + while ((( status == WL_IDLE_STATUS)||(status == WL_SCAN_COMPLETED))&&(--attempts>0)); + }else + { + status = WL_CONNECT_FAILED; + } + return status; +} + +int WiFiClass::begin(char* ssid, uint8_t key_idx, const char *key) +{ + uint8_t status = WL_IDLE_STATUS; + uint8_t attempts = WL_MAX_ATTEMPT_CONNECTION; + + // set encryption key + if (WiFiDrv::wifiSetKey(ssid, strlen(ssid), key_idx, key, strlen(key)) != WL_FAILURE) + { + do + { + delay(WL_DELAY_START_CONNECTION); + status = WiFiDrv::getConnectionStatus(); + }while ((( status == WL_IDLE_STATUS)||(status == WL_SCAN_COMPLETED))&&(--attempts>0)); + }else{ + status = WL_CONNECT_FAILED; + } + return status; +} + +int WiFiClass::begin(char* ssid, const char *passphrase) +{ + uint8_t status = WL_IDLE_STATUS; + uint8_t attempts = WL_MAX_ATTEMPT_CONNECTION; + + // set passphrase + if (WiFiDrv::wifiSetPassphrase(ssid, strlen(ssid), passphrase, strlen(passphrase))!= WL_FAILURE) + { + do + { + delay(WL_DELAY_START_CONNECTION); + status = WiFiDrv::getConnectionStatus(); + } + while ((( status == WL_IDLE_STATUS)||(status == WL_SCAN_COMPLETED))&&(--attempts>0)); + }else{ + status = WL_CONNECT_FAILED; + } + return status; +} + +void WiFiClass::config(IPAddress local_ip) +{ + WiFiDrv::config(1, (uint32_t)local_ip, 0, 0); +} + +void WiFiClass::config(IPAddress local_ip, IPAddress dns_server) +{ + WiFiDrv::config(1, (uint32_t)local_ip, 0, 0); + WiFiDrv::setDNS(1, (uint32_t)dns_server, 0); +} + +void WiFiClass::config(IPAddress local_ip, IPAddress dns_server, IPAddress gateway) +{ + WiFiDrv::config(2, (uint32_t)local_ip, (uint32_t)gateway, 0); + WiFiDrv::setDNS(1, (uint32_t)dns_server, 0); +} + +void WiFiClass::config(IPAddress local_ip, IPAddress dns_server, IPAddress gateway, IPAddress subnet) +{ + WiFiDrv::config(3, (uint32_t)local_ip, (uint32_t)gateway, (uint32_t)subnet); + WiFiDrv::setDNS(1, (uint32_t)dns_server, 0); +} + +void WiFiClass::setDNS(IPAddress dns_server1) +{ + WiFiDrv::setDNS(1, (uint32_t)dns_server1, 0); +} + +void WiFiClass::setDNS(IPAddress dns_server1, IPAddress dns_server2) +{ + WiFiDrv::setDNS(2, (uint32_t)dns_server1, (uint32_t)dns_server2); +} + +int WiFiClass::disconnect() +{ + return WiFiDrv::disconnect(); +} + +uint8_t* WiFiClass::macAddress(uint8_t* mac) +{ + uint8_t* _mac = WiFiDrv::getMacAddress(); + memcpy(mac, _mac, WL_MAC_ADDR_LENGTH); + return mac; +} + +IPAddress WiFiClass::localIP() +{ + IPAddress ret; + WiFiDrv::getIpAddress(ret); + return ret; +} + +IPAddress WiFiClass::subnetMask() +{ + IPAddress ret; + WiFiDrv::getSubnetMask(ret); + return ret; +} + +IPAddress WiFiClass::gatewayIP() +{ + IPAddress ret; + WiFiDrv::getGatewayIP(ret); + return ret; +} + +char* WiFiClass::SSID() +{ + return WiFiDrv::getCurrentSSID(); +} + +uint8_t* WiFiClass::BSSID(uint8_t* bssid) +{ + uint8_t* _bssid = WiFiDrv::getCurrentBSSID(); + memcpy(bssid, _bssid, WL_MAC_ADDR_LENGTH); + return bssid; +} + +int32_t WiFiClass::RSSI() +{ + return WiFiDrv::getCurrentRSSI(); +} + +uint8_t WiFiClass::encryptionType() +{ + return WiFiDrv::getCurrentEncryptionType(); +} + + +int8_t WiFiClass::scanNetworks() +{ + uint8_t attempts = 10; + uint8_t numOfNetworks = 0; + + if (WiFiDrv::startScanNetworks() == WL_FAILURE) + return WL_FAILURE; + do + { + delay(2000); + numOfNetworks = WiFiDrv::getScanNetworks(); + } + while (( numOfNetworks == 0)&&(--attempts>0)); + return numOfNetworks; +} + +char* WiFiClass::SSID(uint8_t networkItem) +{ + return WiFiDrv::getSSIDNetoworks(networkItem); +} + +int32_t WiFiClass::RSSI(uint8_t networkItem) +{ + return WiFiDrv::getRSSINetoworks(networkItem); +} + +uint8_t WiFiClass::encryptionType(uint8_t networkItem) +{ + return WiFiDrv::getEncTypeNetowrks(networkItem); +} + +uint8_t WiFiClass::status() +{ + return WiFiDrv::getConnectionStatus(); +} + +int WiFiClass::hostByName(const char* aHostname, IPAddress& aResult) +{ + return WiFiDrv::getHostByName(aHostname, aResult); +} + +WiFiClass WiFi; diff --git a/libraries/WiFi/src/WiFiClient.cpp b/libraries/WiFi/src/WiFiClient.cpp new file mode 100644 index 000000000..8fb413499 --- /dev/null +++ b/libraries/WiFi/src/WiFiClient.cpp @@ -0,0 +1,200 @@ +/* + WiFiClient.cpp - Library for Arduino Wifi shield. + Copyright (c) 2011-2014 Arduino LLC. All right reserved. + + 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +extern "C" { + #include "utility/wl_definitions.h" + #include "utility/wl_types.h" + #include "string.h" + #include "utility/debug.h" +} + +#include "WiFi.h" +#include "WiFiClient.h" +#include "WiFiServer.h" +#include "utility/server_drv.h" + + +uint16_t WiFiClient::_srcport = 1024; + +WiFiClient::WiFiClient() : _sock(MAX_SOCK_NUM) { +} + +WiFiClient::WiFiClient(uint8_t sock) : _sock(sock) { +} + +int WiFiClient::connect(const char* host, uint16_t port) { + IPAddress remote_addr; + if (WiFi.hostByName(host, remote_addr)) + { + return connect(remote_addr, port); + } + return 0; +} + +int WiFiClient::connect(IPAddress ip, uint16_t port) { + _sock = getFirstSocket(); + if (_sock != NO_SOCKET_AVAIL) + { + ServerDrv::startClient(uint32_t(ip), port, _sock); + WiFiClass::_state[_sock] = _sock; + + unsigned long start = millis(); + + // wait 4 second for the connection to close + while (!connected() && millis() - start < 10000) + delay(1); + + if (!connected()) + { + return 0; + } + }else{ + Serial.println("No Socket available"); + return 0; + } + return 1; +} + +size_t WiFiClient::write(uint8_t b) { + return write(&b, 1); +} + +size_t WiFiClient::write(const uint8_t *buf, size_t size) { + if (_sock >= MAX_SOCK_NUM) + { + setWriteError(); + return 0; + } + if (size==0) + { + setWriteError(); + return 0; + } + + + if (!ServerDrv::sendData(_sock, buf, size)) + { + setWriteError(); + return 0; + } + if (!ServerDrv::checkDataSent(_sock)) + { + setWriteError(); + return 0; + } + + return size; +} + +int WiFiClient::available() { + if (_sock != 255) + { + return ServerDrv::availData(_sock); + } + + return 0; +} + +int WiFiClient::read() { + uint8_t b; + if (!available()) + return -1; + + ServerDrv::getData(_sock, &b); + return b; +} + + +int WiFiClient::read(uint8_t* buf, size_t size) { + // sizeof(size_t) is architecture dependent + // but we need a 16 bit data type here + uint16_t _size = size; + if (!ServerDrv::getDataBuf(_sock, buf, &_size)) + return -1; + return 0; +} + +int WiFiClient::peek() { + uint8_t b; + if (!available()) + return -1; + + ServerDrv::getData(_sock, &b, 1); + return b; +} + +void WiFiClient::flush() { + while (available()) + read(); +} + +void WiFiClient::stop() { + + if (_sock == 255) + return; + + ServerDrv::stopClient(_sock); + WiFiClass::_state[_sock] = NA_STATE; + + int count = 0; + // wait maximum 5 secs for the connection to close + while (status() != CLOSED && ++count < 50) + delay(100); + + _sock = 255; +} + +uint8_t WiFiClient::connected() { + + if (_sock == 255) { + return 0; + } else { + uint8_t s = status(); + + return !(s == LISTEN || s == CLOSED || s == FIN_WAIT_1 || + s == FIN_WAIT_2 || s == TIME_WAIT || + s == SYN_SENT || s== SYN_RCVD || + (s == CLOSE_WAIT)); + } +} + +uint8_t WiFiClient::status() { + if (_sock == 255) { + return CLOSED; + } else { + return ServerDrv::getClientState(_sock); + } +} + +WiFiClient::operator bool() { + return _sock != 255; +} + +// Private Methods +uint8_t WiFiClient::getFirstSocket() +{ + for (int i = 0; i < MAX_SOCK_NUM; i++) { + if (WiFiClass::_state[i] == NA_STATE) + { + return i; + } + } + return SOCK_NOT_AVAIL; +} + diff --git a/libraries/WiFi/src/WiFiClient.h b/libraries/WiFi/src/WiFiClient.h new file mode 100644 index 000000000..caac8fd6e --- /dev/null +++ b/libraries/WiFi/src/WiFiClient.h @@ -0,0 +1,59 @@ +/* + WiFiClient.cpp - Library for Arduino Wifi shield. + Copyright (c) 2011-2014 Arduino LLC. All right reserved. + + 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef wificlient_h +#define wificlient_h +#include "Arduino.h" +#include "Print.h" +#include "Client.h" +#include "IPAddress.h" + +class WiFiClient : public Client { + +public: + WiFiClient(); + WiFiClient(uint8_t sock); + + uint8_t status(); + virtual int connect(IPAddress ip, uint16_t port); + virtual int connect(const char *host, uint16_t port); + virtual size_t write(uint8_t); + virtual size_t write(const uint8_t *buf, size_t size); + virtual int available(); + virtual int read(); + virtual int read(uint8_t *buf, size_t size); + virtual int peek(); + virtual void flush(); + virtual void stop(); + virtual uint8_t connected(); + virtual operator bool(); + + friend class WiFiServer; + + using Print::write; + +private: + static uint16_t _srcport; + uint8_t _sock; //not used + uint16_t _socket; + + uint8_t getFirstSocket(); +}; + +#endif diff --git a/libraries/WiFi/src/WiFiServer.cpp b/libraries/WiFi/src/WiFiServer.cpp new file mode 100644 index 000000000..cab1dee8f --- /dev/null +++ b/libraries/WiFi/src/WiFiServer.cpp @@ -0,0 +1,108 @@ +/* + WiFiServer.cpp - Library for Arduino Wifi shield. + Copyright (c) 2011-2014 Arduino LLC. All right reserved. + + 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include "utility/server_drv.h" + +extern "C" { + #include "utility/debug.h" +} + +#include "WiFi.h" +#include "WiFiClient.h" +#include "WiFiServer.h" + +WiFiServer::WiFiServer(uint16_t port) +{ + _port = port; +} + +void WiFiServer::begin() +{ + uint8_t _sock = WiFiClass::getSocket(); + if (_sock != NO_SOCKET_AVAIL) + { + ServerDrv::startServer(_port, _sock); + WiFiClass::_server_port[_sock] = _port; + WiFiClass::_state[_sock] = _sock; + } +} + +WiFiClient WiFiServer::available(byte* status) +{ + static int cycle_server_down = 0; + const int TH_SERVER_DOWN = 50; + + for (int sock = 0; sock < MAX_SOCK_NUM; sock++) + { + if (WiFiClass::_server_port[sock] == _port) + { + WiFiClient client(sock); + uint8_t _status = client.status(); + uint8_t _ser_status = this->status(); + + if (status != NULL) + *status = _status; + + //server not in listen state, restart it + if ((_ser_status == 0)&&(cycle_server_down++ > TH_SERVER_DOWN)) + { + ServerDrv::startServer(_port, sock); + cycle_server_down = 0; + } + + if (_status == ESTABLISHED) + { + return client; //TODO + } + } + } + + return WiFiClient(255); +} + +uint8_t WiFiServer::status() { + return ServerDrv::getServerState(0); +} + + +size_t WiFiServer::write(uint8_t b) +{ + return write(&b, 1); +} + +size_t WiFiServer::write(const uint8_t *buffer, size_t size) +{ + size_t n = 0; + + for (int sock = 0; sock < MAX_SOCK_NUM; sock++) + { + if (WiFiClass::_server_port[sock] != 0) + { + WiFiClient client(sock); + + if (WiFiClass::_server_port[sock] == _port && + client.status() == ESTABLISHED) + { + n+=client.write(buffer, size); + } + } + } + return n; +} diff --git a/libraries/WiFi/src/WiFiUdp.cpp b/libraries/WiFi/src/WiFiUdp.cpp new file mode 100644 index 000000000..45298c5bc --- /dev/null +++ b/libraries/WiFi/src/WiFiUdp.cpp @@ -0,0 +1,181 @@ +/* + WiFiUdp.cpp - Library for Arduino Wifi shield. + Copyright (c) 2011-2014 Arduino LLC. All right reserved. + + 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +extern "C" { + #include "utility/debug.h" + #include "utility/wifi_spi.h" +} +#include +#include "utility/server_drv.h" +#include "utility/wifi_drv.h" + +#include "WiFi.h" +#include "WiFiUdp.h" +#include "WiFiClient.h" +#include "WiFiServer.h" + + +/* Constructor */ +WiFiUDP::WiFiUDP() : _sock(NO_SOCKET_AVAIL) {} + +/* Start WiFiUDP socket, listening at local port PORT */ +uint8_t WiFiUDP::begin(uint16_t port) { + + uint8_t sock = WiFiClass::getSocket(); + if (sock != NO_SOCKET_AVAIL) + { + ServerDrv::startServer(port, sock, UDP_MODE); + WiFiClass::_server_port[sock] = port; + _sock = sock; + _port = port; + return 1; + } + return 0; + +} + +/* return number of bytes available in the current packet, + will return zero if parsePacket hasn't been called yet */ +int WiFiUDP::available() { + if (_sock != NO_SOCKET_AVAIL) + { + return ServerDrv::availData(_sock); + } + return 0; +} + +/* Release any resources being used by this WiFiUDP instance */ +void WiFiUDP::stop() +{ + if (_sock == NO_SOCKET_AVAIL) + return; + + ServerDrv::stopClient(_sock); + + _sock = NO_SOCKET_AVAIL; +} + +int WiFiUDP::beginPacket(const char *host, uint16_t port) +{ + // Look up the host first + int ret = 0; + IPAddress remote_addr; + if (WiFi.hostByName(host, remote_addr)) + { + return beginPacket(remote_addr, port); + } + return ret; +} + +int WiFiUDP::beginPacket(IPAddress ip, uint16_t port) +{ + if (_sock == NO_SOCKET_AVAIL) + _sock = WiFiClass::getSocket(); + if (_sock != NO_SOCKET_AVAIL) + { + ServerDrv::startClient(uint32_t(ip), port, _sock, UDP_MODE); + WiFiClass::_state[_sock] = _sock; + return 1; + } + return 0; +} + +int WiFiUDP::endPacket() +{ + return ServerDrv::sendUdpData(_sock); +} + +size_t WiFiUDP::write(uint8_t byte) +{ + return write(&byte, 1); +} + +size_t WiFiUDP::write(const uint8_t *buffer, size_t size) +{ + ServerDrv::insertDataBuf(_sock, buffer, size); + return size; +} + +int WiFiUDP::parsePacket() +{ + return available(); +} + +int WiFiUDP::read() +{ + uint8_t b; + if (available()) + { + ServerDrv::getData(_sock, &b); + return b; + }else{ + return -1; + } +} + +int WiFiUDP::read(unsigned char* buffer, size_t len) +{ + if (available()) + { + uint16_t size = 0; + if (!ServerDrv::getDataBuf(_sock, buffer, &size)) + return -1; + // TODO check if the buffer is too smal respect to buffer size + return size; + }else{ + return -1; + } +} + +int WiFiUDP::peek() +{ + uint8_t b; + if (!available()) + return -1; + + ServerDrv::getData(_sock, &b, 1); + return b; +} + +void WiFiUDP::flush() +{ + while (available()) + read(); +} + +IPAddress WiFiUDP::remoteIP() +{ + uint8_t _remoteIp[4] = {0}; + uint8_t _remotePort[2] = {0}; + + WiFiDrv::getRemoteData(_sock, _remoteIp, _remotePort); + IPAddress ip(_remoteIp); + return ip; +} + +uint16_t WiFiUDP::remotePort() +{ + uint8_t _remoteIp[4] = {0}; + uint8_t _remotePort[2] = {0}; + + WiFiDrv::getRemoteData(_sock, _remoteIp, _remotePort); + uint16_t port = (_remotePort[0]<<8)+_remotePort[1]; + return port; +} +